单点登录CAS使用记(四):为登录页面加上验证码

CAS默认的登录页面样式如下,只有用户名与密码两项验证项目。

现在需要为首页登录加上验证码功能。

第一步:首页对默认登录页面的样式进行了调整,使其看上去还算美观。

在页面上加上了验证码项目。

第二步:导入验证码生成工具包及生成验证码配置

pom.xml中加入如下配置

<dependency>
    <groupId>com.google.code.kaptcha</groupId>
    <artifactId>kaptcha</artifactId>
    <version>2.3.2</version>
</dependency>

web.xml中加入如下配置(只配置了宽高度等其他默认)

    <servlet>
        <servlet-name>captchacode</servlet-name>
        <servlet-class>com.google.code.kaptcha.servlet.KaptchaServlet</servlet-class>
        <init-param>
            <description>边框粗细度。必须是一个大于0的值</description>
            <param-name>kaptcha.border.thickness</param-name>
            <param-value>1</param-value>
        </init-param>
        <init-param>
            <description>图片的宽度</description>
            <param-name>kaptcha.image.width</param-name>
            <param-value>140</param-value>
        </init-param>
        <init-param>
            <description>图片的高度</description>
            <param-name>kaptcha.image.height</param-name>
            <param-value>55</param-value>
        </init-param>
    </servlet>
    <servlet-mapping>
        <servlet-name>captchacode</servlet-name>
        <url-pattern>/captchacode</url-pattern>
    </servlet-mapping>

登录页jsp中

<form:input cssClass="required" cssErrorClass="error" id="imgverifycode" path="imgverifycode" htmlEscape="true" autocomplete="off" placeholder="输入验证码" />
<img id="cimg" src="${base_path}/captchacode" onclick="refreshcaptchacode(this)" title="看不清?点击更换另一个。"/>

JavaScript:

function refreshcaptchacode(obj) {
    obj.setAttribute("src", base_path+ "/captchacode?date=" + new Date());
}

第三步:CAS源码需要做哪些修改?

1.首先将新增项目imgverifycode绑定到表单

打开login-webflow.xml,找到这一段

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

修改为(注意红色加大部分):

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

    <!--  并增加了下面这一段代码 -->
    <action-state id="imgverifycodeValidate">
        <evaluate
            expression="authenticationViaFormAction.validatorCode(flowRequestContext, flowScope.credentials, messageContext)" />
        <transition on="error" to="generateLoginTicket" />
        <transition on="success" to="realSubmit" />
    </action-state>

主要是在登录的工作流中加上了 验证码提交绑定以及验证码验证处理。

其次,在UsernamePasswordCredentials.java中添加验证码字段。

    /** The imgverifycode. */
    @NotNull
    @Size(min = 1, message = "required.imgverifycode")
    private String imgverifycode;

对于的修改一下equals,hascode方法。

    @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 (username != null ? !username.equals(that.username)
                : that.username != null)
            return false;
        if (password != null ? !password.equals(that.password)
                : that.password != null)
            return false;
        if (imgverifycode != null ? !imgverifycode.equals(that.imgverifycode)
                : that.imgverifycode != 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
                + (imgverifycode != null ? imgverifycode.hashCode() : 0);
        return result;
    }

2.添加验证逻辑

注意上一段配置加上了一个action-state:imgverifycodeValidate,执行的是AuthenticationViaFormAction.validatorCode(...)方法

打开AuthenticationViaFormAction.java(cas-server-core工程下),添加如下方法

    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();

        UsernamePasswordCredentials upc = (UsernamePasswordCredentials) credentials;
        String submitAuthcode = upc.getImgverifycode();

        if (!StringUtils.hasText(submitAuthcode))
        {
            populateErrorsInstance(new NullImgVerifyCodeAuthenticationException(),
                    messageContext);
            return "error";
        }

        if (StringUtils.equalsIgnoreCase((String) session.getAttribute(Constants.KAPTCHA_SESSION_KEY), captchacode))
        {
            return "success";
        }
        populateErrorsInstance(new BadImgVerifyCodeAuthenticationException(),
                messageContext);
        return "error";
    }

其中NullImgVerifyCodeAuthenticationException,BadImgVerifyCodeAuthenticationException是仿照源码异常类新增的自定义异常类。

NullImgVerifyCodeAuthenticationException.java

/*
 * Copyright 2007 The JA-SIG Collaborative. All rights reserved. See license
 * distributed with this file and available online at
 * http://www.ja-sig.org/products/cas/overview/license/
 */
package com.tongxiang.cas.auth.handler;

import org.jasig.cas.ticket.TicketException;

/**
 * Generic Bad Credentials Exception. This can be thrown when the system knows
 * the credentials are not valid specificially because they are bad. Subclasses
 * can be specific to a certain type of Credentials
 * (BadUsernamePassowrdCredentials).
 *
 * @author Scott Battaglia
 * @version $Revision$ $Date$
 * @since 3.0
 */
public class NullImgVerifyCodeAuthenticationException extends TicketException
{

    /**
     * Static instance of class to prevent cost incurred by creating new
     * instance.
     */
    public static final NullImgVerifyCodeAuthenticationException ERROR = new NullImgVerifyCodeAuthenticationException();

    /** UID for serializable objects. */
    private static final long serialVersionUID = 3256719585087797044L;

    /**
     * Default constructor that does not allow the chaining of exceptions and
     * uses the default code as the error code for this exception.
     */
    private static final String CODE = "required.imgverifycode";

    /**
     * Default constructor that does not allow the chaining of exceptions and
     * uses the default code as the error code for this exception.
     */
    public NullImgVerifyCodeAuthenticationException()
    {
        super(CODE);
    }

    /**
     * Constructor to allow for the chaining of exceptions. Constructor defaults
     * to default code.
     *
     * @param throwable the chainable exception.
     */
    public NullImgVerifyCodeAuthenticationException(final Throwable throwable)
    {
        super(CODE, throwable);
    }

    /**
     * Constructor method to allow for providing a custom code to associate with
     * this exception.
     *
     * @param code the code to use.
     */
    public NullImgVerifyCodeAuthenticationException(final String code)
    {
        super(code);
    }

    /**
     * Constructor to allow for the chaining of exceptions and use of a
     * non-default code.
     *
     * @param code the user-specified code.
     * @param throwable the chainable exception.
     */
    public NullImgVerifyCodeAuthenticationException(final String code,
            final Throwable throwable)
    {
        super(code, throwable);
    }
}

BadImgVerifyCodeAuthenticationException.java

/*
 * Copyright 2007 The JA-SIG Collaborative. All rights reserved. See license
 * distributed with this file and available online at
 * http://www.ja-sig.org/products/cas/overview/license/
 */
package com.tongxiang.cas.auth.handler;

import org.jasig.cas.ticket.TicketException;

/**
 * Generic Bad Credentials Exception. This can be thrown when the system knows
 * the credentials are not valid specificially because they are bad. Subclasses
 * can be specific to a certain type of Credentials
 * (BadUsernamePassowrdCredentials).
 *
 * @author Scott Battaglia
 * @version $Revision$ $Date$
 * @since 3.0
 */
public class BadImgVerifyCodeAuthenticationException extends TicketException
{

    /**
     * Static instance of class to prevent cost incurred by creating new
     * instance.
     */
    public static final BadImgVerifyCodeAuthenticationException ERROR = new BadImgVerifyCodeAuthenticationException();

    /** UID for serializable objects. */
    private static final long serialVersionUID = 3256719585087797044L;

    /**
     * Default constructor that does not allow the chaining of exceptions and
     * uses the default code as the error code for this exception.
     */
    private static final String CODE = "error.authentication.imgverifycode.bad";

    /**
     * Default constructor that does not allow the chaining of exceptions and
     * uses the default code as the error code for this exception.
     */
    public BadImgVerifyCodeAuthenticationException()
    {
        super(CODE);
    }

    /**
     * Constructor to allow for the chaining of exceptions. Constructor defaults
     * to default code.
     *
     * @param throwable the chainable exception.
     */
    public BadImgVerifyCodeAuthenticationException(final Throwable throwable)
    {
        super(CODE, throwable);
    }

    /**
     * Constructor method to allow for providing a custom code to associate with
     * this exception.
     *
     * @param code the code to use.
     */
    public BadImgVerifyCodeAuthenticationException(final String code)
    {
        super(code);
    }

    /**
     * Constructor to allow for the chaining of exceptions and use of a
     * non-default code.
     *
     * @param code the user-specified code.
     * @param throwable the chainable exception.
     */
    public BadImgVerifyCodeAuthenticationException(final String code,
            final Throwable throwable)
    {
        super(code, throwable);
    }
}

并且,在messages_zh_CN.properties文件中添加对应上面两个异常类的两个异常消息

required.imgverifycode=请输入验证码
error.authentication.imgverifycode.bad=验证码错误

3.验证

OK。




单点登录CAS使用记系列:

时间: 2024-07-30 10:12:55

单点登录CAS使用记(四):为登录页面加上验证码的相关文章

单点登录CAS使用记(一):前期准备以及为CAS-Server配置SSL协议

知识点: SSO:单点登录(Single Sign On),是目前比较流行的企业业务整合的解决方案之一.SSO的定义是在多个应用系统中,用户只需要登录一次就可以访问所有相互信任的应用系统. CAS:耶鲁大学开发的单点登录(Single Sign On)系统称为CAS(Central Authentication Server),他是一个开源的.相对比较简单易用的SSO解决方案. SSL(Secure Sockets Layer 安全套接层),及其继任者传输层安全(Transport Layer

单点登录CAS使用记(八):使用maven的overlay实现无侵入的改造CAS

编写中 单点登录CAS使用记系列: 单点登录CAS使用记(一):前期准备以及为CAS-Server配置SSL协议 单点登录CAS使用记(二):部署CAS服务器以及客户端 单点登录CAS使用记(三):实现自定义验证用户登录 单点登录CAS使用记(四):为登录页面加上验证码 单点登录CAS使用记(五):cas-client不拦截静态资源以及无需登录的请求. 单点登录CAS使用记(六):单点登出.单点注销 单点登录CAS使用记(七):关于服务器超时以及客户端超时的分析 单点登录CAS使用记(八):使用

单点登录CAS使用记(三):实现自定义验证用户登录

问题: CAS自带的用户验证逻辑太过简单,如何像正常网站一样,通过验证DB中的用户数据,来验证用户以及密码的合法性呢? 方案1:CAS默认的JDBC扩展方案: CAS自带了两种简单的通过JDBC方式验证用户的处理器. 1.QueryDatabaseAuthenticationHandler 2.SearchModeSearchDatabaseAuthenticationHandler 这两个处理类位于cas-server-support-jdbc这个扩展工程下. 第一步:改写用户验证处理器 打开

单点登录CAS使用记(五):cas-client不拦截静态资源以及无需登录的请求。

一.问题在哪? 在配置cas-client中,有这么一段配置: <filter> <filter-name>CAS Filter</filter-name> <filter-class>org.jasig.cas.client.authentication.AuthenticationFilter</filter-class> <init-param> <param-name>casServerLoginUrl</p

单点登录CAS使用记(二):部署CAS服务器以及客户端

CAS-Server下载地址:https://www.apereo.org/projects/cas/download-cas CAS-Client下载地址:http://developer.jasig.org/cas-clients/ CAS官方教程: https://wiki.jasig.org/display/CASUM/CAS+on+Windows+Quick+Setup+Guide 版本: CAS Server版本:cas-server-3.4.11 CAS Client版本:cas-

单点登录CAS使用记(六):单点登出、单点注销

单点登出基本上没有啥配置 直接在原来logout的时候,重定向到Cas-Server的logout方法 @RequestSecurity @RequestMapping(value = "loginout", method = { RequestMethod.GET, RequestMethod.POST }) public String loginout(HttpSession session) { session.invalidate(); return "redirec

SpringMVC+Apache Shiro+JPA(hibernate)案例教学(三)给Shiro登录验证加上验证码

序: 给Shiro加入验证码,有多种方式,当然你也可以通过继承修改FormAuthenticationFilter类,通过Shiro去验证验证码.具体实现请百度: 应用Shiro到Web Application(验证码实现) 而今天我要说的,既然使用的SpringMVC,为什么不直接在Controller中就处理验证码验证,让事情变的更简单一点呢? 一.新建ValidateCode.java验证码工具类 package org.shiro.demo.util; import java.util.

单点登录CAS与Spring Security集成(数据库验证,向客户端发送更多信息)

准备工作 CAS server从网上直接下载下来,里面有一个cas-server-webapp的工程,使用Maven命令构建,导入到Eclipse中,便可以直接使用,cas server我使用的是3.5.2版本.客户端,我是使用以前的工程,只要是Web工程就行,cas-client使用的3.2.1,Spring Security使用的是3.1.4,记得Spring Security的3.1.2版本和CAS集成时,当需要CAS Server传比较多的信息给客户端时,客户端的Spring Secur

通过连接池和字段索引,提升单点登录cas的性能

cas是多个系统的中心认证,认证的过程就是用户的登录信息和数据库中的信息匹对的过程,如果某一时刻登录的人数很多,需要频繁的读取数据库,数据库连接的管理就是问题. 前天测试评教时无意之中把单点登录的问题暴露出来了,平时通过cas登录管理端是没有问题的,而200人同时通过cas登陆学生端时出现异常 org.springframework.jdbc.CannotGetJdbcConnectionException: Could not get JDBC Connection; nested excep