1. 程式人生 > >改造CAS單點登入 --- 驗證碼

改造CAS單點登入 --- 驗證碼

至於CAS原理問題這就不多介紹了,想了解的可以參考:

http://blog.chinaunix.net/uid-22816738-id-3525939.html

1.新增支援驗證碼jar包

在cas-server-core的pom.xml新增

<dependency>
           <groupId>com.google.code.kaptcha</groupId> 
           <artifactId>kaptcha</artifactId> 
           <version>2.3</version> 
           <classifier>jdk15</classifier> 
        </dependency>

2.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.UsernamePasswordCredentials增加驗證碼屬性

  /** 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;
    }
 @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>


ok,完成。啟動看一下效果。