cas(五)之验证码

  既然是登录,那么少不了的验证码,所以本篇主要说的是验证码的集成。

  • 新建cas-captcha项目(maven的java项目),整理各个项目之间的关系

  cas-captcha项目的pom文件如下,增加了github上的验证码开源包

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>cas</artifactId>
        <groupId>com.fzhsh</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>cas-captcha</artifactId>

    <properties>
        <version.kcaptcha>0.0.9</version.kcaptcha>
    </properties>
    <dependencies>
        <dependency>
            <groupId>com.github.axet</groupId>
            <artifactId>kaptcha</artifactId>
            <version>${version.kcaptcha}</version>
        </dependency>
        <dependency>
            <groupId>org.jasig.cas</groupId>
            <artifactId>cas-server-core</artifactId>
            <version>${cas.version}</version>
        </dependency>
        <dependency>
            <groupId>jstl</groupId>
            <artifactId>jstl</artifactId>
            <version>1.2</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>servlet-api</artifactId>
            <version>2.5</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>jstl</artifactId>
            <version>1.1.2</version>
            <type>jar</type>
            <scope>provided</scope>
        </dependency>
    </dependencies>
</project>

  需要项目父pom里面新增子项目模块

    <modules>
        <module>cas-server</module>
        <module>cas-captcha</module>
        <module>cas-common</module>
    </modules>

  然后在cas-server项目中新增cas-captcha的依赖

        <dependency>
            <groupId>com.fzhsh</groupId>
            <artifactId>cas-captcha</artifactId>
            <version>1.0</version>
        </dependency>
  • 在cas-captcha编写基于spring-web-flow的规则(cas-server登录的流程是基于spring-web-flow的),需要提供一个验证码凭证,还要需要验证验证码的正确性

  验证码凭证类

public class UsernamePasswordCaptchaCredential extends UsernamePasswordCredentials {

    private String captcha;

    public String getCaptcha() {
        return captcha;
    }

    public void setCaptcha(String captcha) {
        this.captcha = captcha;
    }

    @Override
    public String toString() {
        return this.getUsername();
    }
}

  验证规则类

public class CaptchaValidateAction {

    /** Authentication success result. */
    public static final String SUCCESS = "success";

    /** Authentication failure result. */
    public static final String AUTHENTICATION_FAILURE = "authenticationFailure";

    /** Error result. */
    public static final String ERROR = "error";

    private static final String USER_NAME = "username";
    private static final String PASSWORD = "password";
    private static final String CAPTCHA = "captcha";

    public final String submit(final RequestContext context,
                               final Credential credential, final MessageContext messageContext)
            throws Exception {

        final HttpServletRequest request = WebUtils
                .getHttpServletRequest(context);
        HttpSession session = request.getSession();
        String captcha = (String) session.getAttribute(com.google.code.kaptcha.Constants.KAPTCHA_SESSION_KEY);
        session.removeAttribute(com.google.code.kaptcha.Constants.KAPTCHA_SESSION_KEY);

        String username = request.getParameter(USER_NAME);
        String password = request.getParameter(PASSWORD);
        String submitCaptcha = request.getParameter(CAPTCHA);
        
        //检查用户名是否为空
        if (!StringUtils.hasText(username)) {
            messageContext.addMessage(new MessageBuilder().error().code("required.username").build());
            return ERROR;
        }
        
        //检查密码是否为空
        if (!StringUtils.hasText(password)) {
            messageContext.addMessage(new MessageBuilder().error().code("required.password").build());
            return ERROR;
        }
        if(ignoerCaptcha){
            return SUCCESS;
        }
        //检查是否生成验证码
        if(!StringUtils.hasText(captcha)){
             messageContext.addMessage(new MessageBuilder().error().code("session.captcha.error").build());
             return ERROR;
        }
        //检查验证码是否为空
        if (!StringUtils.hasText(submitCaptcha)
                || !StringUtils.hasText(captcha)) {
            messageContext.addMessage(new MessageBuilder().error().code("required.captcha").build());
            return ERROR;
        }
        if (submitCaptcha.toLowerCase().equals(captcha.toLowerCase())) {
            return SUCCESS;
        }
        messageContext.addMessage(new MessageBuilder().error().code("error.authentication.captcha.bad").build());
        return ERROR;
    }
}

  至此,cas-captcha项目开发结束,下面把验证码逻辑加入cas-server。

  • 配置cas-server,增加验证码逻辑

  在web.xml加上对captcha.jpg的url映射

  <servlet>
    <servlet-name>kaptcha</servlet-name>
    <servlet-class>com.google.code.kaptcha.servlet.KaptchaServlet</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>kaptcha</servlet-name>
    <url-pattern>/captcha.jpg</url-pattern>
  </servlet-mapping>

  在cas-servlet.xml加入CaptchaValidateAction的定义

<bean id="captchaValidateAction" class="com.fzhsh.cas.captcha.CaptchaValidateAction"></bean>

  在login-webflow.xml增加验证码的流程

  1,将UsernamePasswordCredentials替换成自定义的凭证

<!--<var name="credentials" class="org.jasig.cas.authentication.principal.UsernamePasswordCredentials" />-->
    <var name="credentials" class="com.fzhsh.cas.captcha.UsernamePasswordCaptchaCredential" />

  2,在viewLoginForm中增加验证码,并且转向验证码验证流程

<view-state id="viewLoginForm" view="casLoginView" model="credentials">
        <binder>
            <binding property="username" />
            <binding property="password" />
            <!-- add -->
            <binding property="captcha" />
        </binder>
        <on-entry>
            <set name="viewScope.commandName" value="'credentials'" />
        </on-entry>
        <transition on="submit" bind="true" validate="true" to="captchaValidate">
            <evaluate expression="authenticationViaFormAction.doBind(flowRequestContext, flowScope.credentials)" />
        </transition>
    </view-state>

  3,增加验证码验证流程

    <!-- add start -->
    <action-state id="captchaValidate">
        <evaluate expression="captchaValidateAction.submit(flowRequestContext, flowScope.credential, messageContext)" />
        <transition on="error" to="generateLoginTicket" />
        <transition on="success" to="realSubmit" />
        <transition on="authenticationFailure" to="handleAuthenticationFailure" />
    </action-state>
    <!-- add end -->

  4,i18n国际化properties文件处理,当前只支持英语,在src/main/resources文件夹下拷贝一份messages_en.properties,加入CaptchaValidateAction国际化需要的内容

# captcha
screen.welcome.label.captcha=validate code:
screen.welcome.label.captcha.accesskey=accesskey
required.captcha=captcha is a required field
error.authentication.captcha.bad=error validate code

  在casLoginView.jsp里面找到<div class="row check">,然后在前面增加验证码输入框

  <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-server项目里面来
posted @ 2017-05-16 13:59  風之殤  阅读(583)  评论(0)    收藏  举报