CAS添加验证码功能
1. cas.war 下面的web-inf/web.xml lib添加 kaptcha.jar
kaptcha.jar通过maven获取
<dependency> <groupId>com.github.axet</groupId> <artifactId>kaptcha</artifactId> <version>0.0.9</version> </dependency>
这个maven 包含两个 jar 另一个是filters-2.0.235.jar
2. cas.war 下面的web-inf/web.xml添加验证码映射
<servlet> <servlet-name>Kaptcha</servlet-name> <servlet-class>com.google.code.kaptcha.servlet.KaptchaServlet</servlet-class> <init-param> <param-name>kaptcha.border</param-name> <param-value>no</param-value> </init-param> <init-param> <param-name>kaptcha.textproducer.char.space</param-name> <param-value>5</param-value> </init-param> <init-param> <param-name>kaptcha.textproducer.char.length</param-name> <param-value>5</param-value> </init-param> </servlet> <servlet-mapping> <servlet-name>Kaptcha</servlet-name> <url-pattern>/captcha.jpg</url-pattern> </servlet-mapping>
3. cas中 UsernamePasswordCredentials 类增加验证码属性 authcode
/** The authcode. */ @NotNull @Size(min=1, message = "required.authcode") private String authcode; public String getAuthcode() { return authcode; } public void setAuthcode(String authcode) { this.authcode = authcode; } /** * @return Returns the password. */ public final String getPassword() { return this.password; }
并且重写equals和hashCode方法
@Override public boolean equals(final Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; UsernamePasswordCredentials that = (UsernamePasswordCredentials) o; if (password != null ? !password.equals(that.password) : that.password != null) return false; if (username != null ? !username.equals(that.username) : that.username != null) return false; if (authcode != null ? !authcode.equals(that.authcode) : that.authcode != null) return false; return true; } @Override public int hashCode() { int result = username != null ? username.hashCode() : 0; result = 31 * result + (password != null ? password.hashCode() : 0); result = 31 * result + (authcode != null ? authcode.hashCode() : 0); return result; }
4. AuthenticationViaFormAction 类增加验证方法
public final String validatorCode(final RequestContext context, final Credentials credentials, final MessageContext messageContext) throws Exception { final HttpServletRequest request = WebUtils.getHttpServletRequest(context); HttpSession session = request.getSession(); String authcode = (String)session.getAttribute(com.google.code.kaptcha.Constants.KAPTCHA_SESSION_KEY); session.removeAttribute(com.google.code.kaptcha.Constants.KAPTCHA_SESSION_KEY); UsernamePasswordCredentials upc = (UsernamePasswordCredentials)credentials; String submitAuthcode =upc.getAuthcode(); if(!StringUtils.hasText(submitAuthcode) || !StringUtils.hasText(authcode)){ populateErrorsInstance(new NullAuthcodeAuthenticationException(),messageContext); return "error"; } if(submitAuthcode.equals(authcode)){ return "success"; } populateErrorsInstance(new BadAuthcodeAuthenticationException(),messageContext); return "error"; }
NullAuthcodeAuthenticationException 、BadAuthcodeAuthenticationException为定义的异常类,取得异常编码
/* * Licensed to Jasig under one or more contributor license * agreements. See the NOTICE file distributed with this work * for additional information regarding copyright ownership. * Jasig licenses this file to you under the Apache License, * Version 2.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a * copy of the License at the following location: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ package org.jasig.cas.authentication.handler; import org.jasig.cas.ticket.TicketException; /** * The exception to throw when we know the authcode is null * * @author Scott Battaglia * @version $Revision$ $Date$ * @since 3.0 */ public class NullAuthcodeAuthenticationException extends TicketException { /** Serializable ID for unique id. */ private static final long serialVersionUID = 5501212207531289993L; /** Code description. */ public static final String CODE = "required.authcode"; /** * Constructs a TicketCreationException with the default exception code. */ public NullAuthcodeAuthenticationException() { super(CODE); } /** * Constructs a TicketCreationException with the default exception code and * the original exception that was thrown. * * @param throwable the chained exception */ public NullAuthcodeAuthenticationException(final Throwable throwable) { super(CODE, throwable); }}
/* * Licensed to Jasig under one or more contributor license * agreements. See the NOTICE file distributed with this work * for additional information regarding copyright ownership. * Jasig licenses this file to you under the Apache License, * Version 2.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a * copy of the License at the following location: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ package org.jasig.cas.authentication.handler; import org.jasig.cas.ticket.TicketException; /** * The exception to throw when we know the authcoe is not correct * * @author Scott Battaglia * @version $Revision$ $Date$ * @since 3.0 */ public class BadAuthcodeAuthenticationException extends TicketException { /** Serializable ID for unique id. */ private static final long serialVersionUID = 5501212207531289993L; /** Code description. */ public static final String CODE = "error.authentication.authcode.bad"; /** * Constructs a TicketCreationException with the default exception code. */ public BadAuthcodeAuthenticationException() { super(CODE); } /** * Constructs a TicketCreationException with the default exception code and * the original exception that was thrown. * * @param throwable the chained exception */ public BadAuthcodeAuthenticationException(final Throwable throwable) { super(CODE, throwable); }}
5. login_webflow.xml 修改登录验证流程
<view-state id="viewLoginForm" view="casLoginView" model="credentials"> <binder> <binding property="username" /> <binding property="password" /> <binding property="authcode" /> </binder> <on-entry> <set name="viewScope.commandName" value="'credentials'" /> </on-entry> <transition on="submit" bind="true" validate="true" to="authcodeValidate"> <evaluate expression="authenticationViaFormAction.doBind(flowRequestContext, flowScope.credentials)" /> </transition> </view-state> <action-state id="authcodeValidate"> <evaluate expression="authenticationViaFormAction.validatorCode(flowRequestContext, flowScope.credentials, messageContext)" /> <transition on="error" to="generateLoginTicket" /> <transition on="success" to="realSubmit" /> </action-state>
6. 增加国际化显示信息
在messages_zh_CN.properties文件中添加,其他国家语言类似添加
screen.welcome.label.authcode=\u9A8C\u8BC1\u7801:
screen.welcome.label.authcode.accesskey=a
required.authcode=\u5FC5\u987B\u5F55\u5165\u9A8C\u8BC1\u7801\u3002
error.authentication.authcode.bad=\u9A8C\u8BC1\u7801\u8F93\u5165\u6709\u8BEF\u3002
7. 登录页面casLoginView.jsp添加验证码输入框
<div class="row fl-controls-left"> <label for="authcode"><spring:message code="screen.welcome.label.authcode" /></label> <spring:message code="screen.welcome.label.authcode.accesskey" var="authcodeAccessKey" /> <table> <tr> <td> <form:input cssClass="required" cssErrorClass="error" id="authcode" size="10" tabindex="2" path="authcode" accesskey="${authcodeAccessKey}" htmlEscape="true" autocomplete="off" /> </td> <td align="left" valign="bottom" style="vertical-align: bottom;"> <img alt="<spring:message code="required.authcode" />" onclick="this.src='captcha.jpg?'+Math.random()" width="93" height="30" src="captcha.jpg"> </td> </tr> </table> </div> <div class="row check"> <input id="warn" name="warn" value="true" tabindex="3" accesskey="<spring:message code="screen.welcome.label.warn.accesskey" />" type="checkbox" /> <label for="warn"><spring:message code="screen.welcome.label.warn" /></label> </div>
以上操作有些要修改源码,所以还是要把源码下载下来部署到Eclipse上修改比较方便,修改后编译成class文件放入到cas web里面