cas4服务端缺少验证码功能,本文讲述是如何在cas-server中增加验证码功能,cas版本采用cas-server4.0.0进行讲述,关于单点登录源码下载问题这里就不在做阐述如果需要可以在本站素文宅blog.yoodb.com搜索相关内容。
1、在cas4集成验证码前确认是否有关于google验证码jar包,如果没有下载kaptcha-2.3.2.jar放入到项目中,maven项目中pom.xml增加如下代码:
<dependency> <groupId>com.google.code</groupId> <artifactId>kaptcha</artifactId> <version>2.3.2</version> </dependency>
本站kaptcha-2.3.2.jar包下载是通过私有仓库的,如果下载失败请手动添加jar包到项目中。
2、首先在cas-server-webapp项目的web.xml验证码servlet代码:
<!-- 验证码功能 --> <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、新增验证码处理类
1) 新建UsernamePasswordCaptchaCredential类,继承org.jasig.cas.authentication.UsernamePasswordCredential,添加验证码字段并重写equals和hashCode方法,具体代码如下:
package org.jasig.cas.authentication; import javax.validation.constraints.NotNull; import javax.validation.constraints.Size; import org.apache.commons.lang.builder.HashCodeBuilder; public class UsernamePasswordCaptchaCredential extends UsernamePasswordCredential { private static final long serialVersionUID = 1L; @NotNull @Size(min = 1, message = "required.authcode") private String authcode; public final String getAuthcode() { return authcode; } public final void setAuthcode(String authcode) { this.authcode = authcode; } @Override public boolean equals(final Object o) { if (this == o) { return true; } if (o == null || getClass() != o.getClass()) { return false; } final UsernamePasswordCaptchaCredential that = (UsernamePasswordCaptchaCredential) o; if (getPassword() != null ? !getPassword().equals(that.getPassword()) : that.getPassword() != null) { return false; } if (getPassword() != null ? !getPassword().equals(that.getPassword()) : that.getPassword() != null) { return false; } if (authcode != null ? !authcode.equals(that.authcode) : that.authcode != null) return false; return true; } @Override public int hashCode() { return new HashCodeBuilder().append(getUsername()) .append(getPassword()).append(authcode).toHashCode(); } }
2) 新建AuthenticationViaFormCaptchaAction类,继承org.jasig.cas.web.flow.AuthenticationViaFormAction类,增加验证码方法具体代码如下:
package org.jasig.cas.authentication; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpSession; import org.apache.commons.lang.StringUtils; 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.webflow.execution.RequestContext; public class AuthenticationViaFormCaptchaAction extends AuthenticationViaFormAction { public final String validatorCode(final RequestContext context, final Credential 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); UsernamePasswordCaptchaCredential upc = (UsernamePasswordCaptchaCredential) credentials; String submitAuthcode = upc.getAuthcode(); if (StringUtils.isEmpty(submitAuthcode) || StringUtils.isEmpty(authcode)) { populateErrorsInstance(new NullAuthcodeAuthenticationException(), messageContext); return "error"; } if (submitAuthcode.equals(authcode)) { return "success"; } populateErrorsInstance(new BadAuthcodeAuthenticationException(), messageContext); return "error"; } private void populateErrorsInstance(final RootCasException e, final MessageContext messageContext) { try { messageContext.addMessage(new MessageBuilder().error() .code(e.getCode()).defaultText(e.getCode()).build()); } catch (final Exception fe) { logger.error(fe.getMessage(), fe); } } }
3) 其中NullAuthcodeAuthenticationException和BadAuthcodeAuthenticationException是自定义的异常类,用于取得异常码,具体代码如下:
BadAuthcodeAuthenticationException.java
package org.jasig.cas.authentication; import org.jasig.cas.authentication.RootCasException; public class BadAuthcodeAuthenticationException extends RootCasException { private static final long serialVersionUID = 5501212207531289993L; public static final String CODE = "error.authentication.authcode.bad"; public BadAuthcodeAuthenticationException() { super(CODE); } public BadAuthcodeAuthenticationException(final Throwable throwable) { super(CODE, throwable); } }
NullAuthcodeAuthenticationException.java
package org.jasig.cas.authentication; import org.jasig.cas.authentication.RootCasException; public class NullAuthcodeAuthenticationException extends RootCasException { private static final long serialVersionUID = 5501212207531289993L; public static final String CODE = "required.authcode"; public NullAuthcodeAuthenticationException() { super(CODE); } public NullAuthcodeAuthenticationException(final Throwable throwable) { super(CODE, throwable); } }
4、修改验证码配置文件
1) login-webflow.xml修改登录验证流程:
<var name="credential" class="org.jasig.cas.authentication.UsernamePasswordCredential" /> 修改为: <var name="credential" class="org.jasig.cas.authentication.UsernamePasswordCaptchaCredential" /> <!-- --> <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> <action-state id="generateLoginTicket"> <evaluate expression="generateLoginTicketAction.generate(flowRequestContext)" /> <transition on="generated" to="viewLoginForm" /> </action-state> 修改为: <view-state id="viewLoginForm" view="casLoginView" model="credential"> <binder> <binding property="username" /> <binding property="password" /> <binding property="authcode" /> </binder> <on-entry> <set name="viewScope.commandName" value="'credential'" /> </on-entry> <transition on="submit" bind="true" validate="true" to="authcodeValidate"> <evaluate expression="authenticationViaFormAction.doBind(flowRequestContext, flowScope.credential)" /> </transition> </view-state> <action-state id="authcodeValidate"> <evaluate expression="authenticationViaFormAction.validatorCode(flowRequestContext, flowScope.credential, messageContext)" /> <transition on="error" to="generateLoginTicket" /> <transition on="success" to="realSubmit" /> </action-state>
2) 修改cas-servlet.xml里关于authenticationViaFormAction的bean配置:
<bean id="authenticationViaFormAction" class="org.jasig.cas.authentication.AuthenticationViaFormAction" p:centralAuthenticationService-ref="centralAuthenticationService" p:warnCookieGenerator-ref="warnCookieGenerator" p:ticketRegistry-ref="ticketRegistry"/> 修改为: <bean id="authenticationViaFormAction" class="org.jasig.cas.authentication.AuthenticationViaFormCaptchaAction" p:centralAuthenticationService-ref="centralAuthenticationService" p:warnCookieGenerator-ref="warnCookieGenerator" p:ticketRegistry-ref="ticketRegistry"/>
5、增加国际化显示信息:
screen.welcome.label.authcode=验证码:
screen.welcome.label.authcode.accesskey=a
required.authcode=必须录入验证码。
error.authentication.authcode.bad=验证码输入有误。
6、登录页面casLoginView.jsp添加验证码输入框:
<section 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 style="vertical-align: bottom"> <img onclick="this.src='captcha.jpg?'+Math.random()" width="93" height="30" src="captcha.jpg"> </td> </tr> </table> </section>
如果打开页面后报java.lang.NoClassDefFoundError: com/jhlabs/image/RippleFilter异常,解决方法参考:http://blog.yoodb.com/yoodb/article/detail/1280,如果对本站blog.yoodb.com有兴趣欢迎收藏。