轉自 http://blog.csdn.net/attackmind/article/details/52052502 css
一、在cas工程的web.xml增長驗證碼功能的支持:html
<!-- 驗證碼功能 --> <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>
二、新建一個類UsernamePasswordCredentialWithAuthCode,該類繼承了java
org.jasig.cas.authentication.UsernamePasswordCredential,添加一個驗證碼字段,web
而且重寫equals和hashCode方法,添加關於驗證碼比較的信息spring
package org.spire.cas.core.authentication; import javax.validation.constraints.NotNull; import javax.validation.constraints.Size; import org.apache.commons.lang3.builder.HashCodeBuilder; import org.jasig.cas.authentication.UsernamePasswordCredential; public class UsernamePasswordCredentialWithAuthCode extends UsernamePasswordCredential { /** * 帶驗證碼的登陸界面 */ private static final long serialVersionUID = 1L; /** 驗證碼*/ @NotNull @Size(min = 1, message = "required.authcode") private String authcode; /** * * @return */ public final String getAuthcode() { return authcode; } /** * * @param 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 UsernamePasswordCredentialWithAuthCode that = (UsernamePasswordCredentialWithAuthCode) 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(); } }
3.新建一個類AuthenticationViaFormActionWithAuthCode,該類繼承了org.jasig.cas.web.flow.AuthenticationViaFormAction類,增長一個驗證碼方法validatorCode:express
package org.spire.cas.core.authentication; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpSession; import org.apache.commons.lang3.StringUtils; import org.jasig.cas.authentication.Credential; import org.jasig.cas.authentication.RootCasException; 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; /** * 驗證碼校驗類 * * @author Langyou02 * */ public class AuthenticationViaFormActionWithAuthCode extends AuthenticationViaFormAction { /** * authcode check */ 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); UsernamePasswordCredentialWithAuthCode upc = (UsernamePasswordCredentialWithAuthCode) 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); } } }
其中NullAuthcodeAuthenticationException和BadAuthcodeAuthenticationException是自定義的異常類,用於取得異常碼:apache
/* * 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.spire.cas.core.authentication; import org.jasig.cas.authentication.RootCasException; /** * The exception to throw when we know the authcode is null * * @author Scott Battaglia * @version $Revision$ $Date$ * @since 3.0 */ public class NullAuthcodeAuthenticationException extends RootCasException { /** 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.spire.cas.core.authentication; import org.jasig.cas.authentication.RootCasException; /** * 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 RootCasException { /** 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); }}
四、在spire_cas工程的login_webflow.xml修改登陸驗證流程:服務器
<view-state id="viewLoginForm" view="casLoginView" model="credential"> <binder> <binding property="username" required="true"/> <binding property="password" required="true"/> <binding property="authcode" required="true"/> <binding property="rememberMe" /> </binder> <on-entry> <set name="viewScope.commandName" value="'credential'"/> <!-- <evaluate expression="samlMetadataUIParserAction" /> --> </on-entry> <transition on="submit" bind="true" validate="true" to="authcodeValidate"> </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>
並修改cas-servlet.xmlbean id ="AuthenticationViaFormAction"的class="org.spire.cas.core.authentication.AuthenticationViaFormActionWithAuthCode";session
五、增長國際化顯示信息:app
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
六、登陸頁面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>
七、若是要默認中文頁面顯示,修改cas-servlet.xml 下的local Resolver默認值爲zh_CN:
<bean id="localeResolver" class="org.springframework.web.servlet.i18n.CookieLocaleResolver" p:defaultLocale="zh_CN" />
八、效果圖(spire_cas是另一個web工程登陸跳轉到cas服務器認證):
九、參考博文:http://blog.csdn.net/zhu_tianwei/article/details/19153549