CAS增加验证码
1.1开始增加验证码
第一部分:
(1)在WEB-INF下找到并打开login-webflow.xml,找到:<var name="credential" class="org.jasig.cas.authentication.UsernamePasswordCredential" />,
该配置的作用是,在登录时收集用户名密码信息的。所以我们需要扩展增加验证码字段的收集。新建包:org.chengli.cas.credential,
新建类:CustomUsernamePasswordCredential并继承org.jasig.cas.authentication.UsernamePasswordCredential类,增加验证码字段,代码如下:
package org.chengli.cas.credential;
import org.jasig.cas.authentication.UsernamePasswordCredential;
public class CustomUsernamePasswordCredential extends
UsernamePasswordCredential {
private static final long serialVersionUID = 5034129937759981063L;
private String captcha;
public String getCaptcha() {
return captcha;
}
public void setCaptcha(String captcha) {
this.captcha = captcha;
}
}
修改前:
<var name="credential" class="org.jasig.cas.authentication.UsernamePasswordCredential" />
修改后:
<var name="credential" class="org.chengli.cas.credential.CustomUsernamePasswordCredential" />
修改前:
<view-state id="viewLoginForm" view="casLoginView" model="credential">
<binder>
<binding property="username" />
<binding property="password" />
</binder>
<on-entry>
<set name="viewScope.commandName" value="'credential'" />
</on-entry>
<transition on="submit" bind="true" validate="true" to="realSubmit">
<evaluate expression="authenticationViaFormAction.doBind(flowRequestContext, flowScope.credential)" />
</transition>
</view-state>
修改后:
<view-state id="viewLoginForm" view="casLoginView" model="credential">
<binder>
<binding property="username" />
<binding property="password" />
<binding property="captcha" />
</binder>
<on-entry>
<set name="viewScope.commandName" value="'credential'" />
</on-entry>
<transition on="submit" bind="true" validate="true" to="customValidator">
<evaluate expression="authenticationViaFormAction.doBind(flowRequestContext, flowScope.credential)" />
</transition>
</view-state>
(3)在login-webflow.xm增加l配置
<action-state id="customValidator">
<evaluate expression="authenticationViaFormAction.customValidator(flowRequestContext, flowScope.credential, messageContext)"></evaluate>
<transition on="error" to="generateLoginTicket" />
<transition on="success" to="realSubmit" />
</action-state>
但是CAS提供的authenticationViaFormAction类根本就没有customValidator方法,所以我们需要实现该方法,authenticationViaFormAction Bean定义
在WEB-INF->cas-servlet.xml中,打开cas-servlet.xml,找到bean id为authenticationViaFormAction的定义,修改改定义类。如下:
修改前:
<bean id="authenticationViaFormAction" class="org.jasig.cas.web.flow.AuthenticationViaFormAction"
p:centralAuthenticationService-ref="centralAuthenticationService"
p:warnCookieGenerator-ref="warnCookieGenerator"
p:ticketRegistry-ref="ticketRegistry"/>
修改后:
<bean id="authenticationViaFormAction" class="org.chengli.cas.validator.CustomAuthenticationViaFormAction"
p:centralAuthenticationService-ref="centralAuthenticationService"
p:warnCookieGenerator-ref="warnCookieGenerator"
p:ticketRegistry-ref="ticketRegistry"/>
(5)新建包:org.chengli.cas.validator,新建类:CustomAuthenticationViaFormAction并继承AuthenticationViaFormAction,增加方法:customValidator,
验证码使用的是GOOGLE的kaptcha,在pom.xml增加依赖,如下:
<dependency>
<groupId>com.google.code.kaptcha</groupId>
<artifactId>kaptcha</artifactId>
<version>2.3.2</version>
</dependency>
CustomAuthenticationViaFormAction类代码如下:
package org.chengli.cas.validator;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import org.chengli.cas.credential.CustomUsernamePasswordCredential;
import org.jasig.cas.authentication.Credential;
import org.jasig.cas.web.flow.AuthenticationViaFormAction;
import org.jasig.cas.web.support.WebUtils;
import org.springframework.binding.message.MessageBuilder;
import org.springframework.binding.message.MessageContext;
import org.springframework.util.StringUtils;
import org.springframework.webflow.execution.Event;
import org.springframework.webflow.execution.RequestContext;
import com.google.code.kaptcha.Constants;
public class CustomAuthenticationViaFormAction extends
AuthenticationViaFormAction {
public final Event customValidator(RequestContext context,
Credential credential, MessageContext messageContext) {
HttpServletRequest request = WebUtils.getHttpServletRequest(context);
HttpSession session = request.getSession();
String captcha = (String) session.getAttribute(Constants.KAPTCHA_SESSION_KEY);
session.removeAttribute(Constants.KAPTCHA_SESSION_KEY);
CustomUsernamePasswordCredential cuCredential = (CustomUsernamePasswordCredential) credential;
String submitCaptcha= cuCredential.getCaptcha();
if (!StringUtils.hasText(submitCaptcha)) {
messageContext.addMessage(new MessageBuilder().error().code("login.required.captcha").build());
return new Event(this, ERROR);
}
if (submitCaptcha.equals(captcha)) {
return new Event(this, SUCCESS);
}
messageContext.addMessage(new MessageBuilder().error().code("login.captcha.error").build());
return new Event(this, ERROR);
}
}
(6)CAS实现了国际化支持,错误信息都放在国际化文件中,在messages.properties、messages_zh_CN.properties加入以下内容:
login.required.captcha=请输入验证码
login.captcha.error=验证码错误
login.captcha.error=验证码错误
如果需要实现更多语言只需要在相应的国际化文件中加入即可。
(7)打开web.xml加入以下代码:
<servlet>
<servlet-name>Kaptcha</servlet-name>
<servlet-class>com.google.code.kaptcha.servlet.KaptchaServlet</servlet-class>
<init-param>
<param-name>kaptcha.image.width</param-name>
<param-value>200</param-value>
</init-param>
<init-param>
<param-name>kaptcha.image.height</param-name>
<param-value>50</param-value>
</init-param>
<init-param>
<param-name>kaptcha.textproducer.char.length</param-name>
<param-value>4</param-value>
</init-param>
<init-param>
<param-name>kaptcha.noise.impl</param-name>
<param-value>com.google.code.kaptcha.impl.NoNoise</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>Kaptcha</servlet-name>
<url-pattern>/kaptcha.jpg</url-pattern>
</servlet-mapping>
(8)在登录页面form中加入以下代码:
<input id="captcha" type="text" name="captcha" placeholder="请输入验证码"/>
<img class="security-code-img" src="kaptcha.jpg" >
(9)到这里就OK啦,启动TOMCAT试试看吧,效果图如下。。。
第二部分:
可能还有的需求,在用户打开浏览器第一次登录的时候不需要输入验证码,如果登录用户名或者密码错了之后,再进行登录就需要验证码,
那么接下来,将说说怎么弄,只是个人实现的方法,如果有更好的方法欢迎大家探讨。
(1)创建包:org.chengli.cas.constans,创建类:CustomConstants。代码如下:
package org.chengli.cas.constans;
public interface CustomConstants {
String LOGIN_FIRST = "LOGIN_FIRST";
String FIRST = "FIRST";
String NOTFIRST = "NOTFIRST";
}
(2)在CustomAuthenticationViaFormAction类中customValidator方法HttpSession session = request.getSession();下面 加入以下代码:
Object loginObject = session.getAttribute(CustomConstants.LOGIN_FIRST);
if(loginObject == null || CustomConstants.FIRST.equals(String.valueOf(loginObject))){
session.setAttribute(CustomConstants.LOGIN_FIRST, CustomConstants.NOTFIRST);
return new Event(this, SUCCESS);
}
注:我使用的session中存储,也就是说你输入密码错误后,需要你输入验证码,但是你关闭浏览器后在打开还是不需要你输入的。你也可以
基于cookie实现哦,原理一样。
(3)在登录页面中,对验证码加上以下判断:
<c:if test="${sessionScope.LOGIN_FIRST == 'NOTFIRST'}">
这里放验证码的代码哦
</c:if>
(4)到这里基本上就已经实现了,如果你的有问题可以留言一起讨论。效果如下: