`
jkam
  • 浏览: 44305 次
  • 性别: Icon_minigender_1
  • 来自: piǎ 县
社区版块
存档分类
最新评论

Spring JDBC实践之--Yale CAS登录模块的一个典型的客户化

阅读更多
  项目使用Yale CAS+Spring Security实现单点登录以及权限验证
需要对Yale CAS的登录模块进行一下改动,如果用户输入帐号密码失败次数超过3次的时候,要把帐号锁定,这样要等管理员解锁以后才可以再次登录这个帐号。
Yale CAS的登录是个典型的密码验证模块,不能提供上述需求,这就需要对CAS的登录部分做些改动
(暂且不考虑这个需求是不是合理,单纯从技术角度来实现这个需求)
具体分析如下:

  • 1. 一个帐户需要多记录两个属性:密码输错的次数以及帐户是否可登录;
  • 2. 用户提交登录申请的时候,先检验该帐户是否可登录,如果是,继续进行下面的,如果否,返回登录失败信息;
  • 3. 校验用户帐户和密码,如果密码正确,返回登录成功,如果密码错误,继续进行下面的;
  • 4. 该帐户的密码输错次数加1,并比较现在的输错次数是否小于3(可配置),如果是,返回登录失败信息,如果否,继续进行下面的;
  • 5. 将帐户是否可登录属性设置为否,返回登录失败信息。


综合上述分析,实现如下:
  • 1. 数据库中设计帐户信息时加两个字段failureTimes和isValid来记录错误登录次数和是否被锁定
  • 2. 重写CAS的密码校验模块,
package com.cas;

import org.inspektr.common.ioc.annotation.NotNull;
import org.jasig.cas.adaptors.jdbc.AbstractJdbcUsernamePasswordAuthenticationHandler;
import org.jasig.cas.authentication.handler.AuthenticationException;
import org.jasig.cas.authentication.handler.BadPasswordAuthenticationException;
import org.jasig.cas.authentication.handler.UnknownUsernameAuthenticationException;
import org.jasig.cas.authentication.principal.UsernamePasswordCredentials;
import org.springframework.dao.IncorrectResultSizeDataAccessException;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;

/**
 * Class that if provided a query that returns a password (parameter of query must be username) will compare that
 * password to a translated version of the password provided by the user. If they match, then authentication succeeds.
 * Default password translator is plaintext translator.
 *
 * @Date 2009-5-23
 */
public class JdbcUsernamePasswordAuthHandlerImpl extends AbstractJdbcUsernamePasswordAuthenticationHandler {

    // it's better to move below properties to external configure file, for example 'maxFailureTimes'
    private static final String QUERY_USER_SQL = "select * from user_info where username = ?";
    private static final String FAILURE_TRIGGER_SQL = "update user_info set failureTimes = ? where username = ?";
    private static final String LOCK_USER_SQL = "update user_info set failureTimes = ?, isValid = ? where username = ?";

    @NotNull
    private String maxFailureTimes;

    /**
     * @param paraMaxFailureTimes
     *            the maxFailureTimes to set
     */
    public void setMaxFailureTimes(String paraMaxFailureTimes) {
        this.maxFailureTimes = paraMaxFailureTimes;
    }

    /**
     * authenticate username password internal
     *
     * @param credentials
     *            credentials
     * @throws AuthenticationException
     *             AuthenticationException
     * @return true if user login success
     * @see org.jasig.cas.authentication.handler.support.AbstractUsernamePasswordAuthenticationHandler
     *      #authenticateUsernamePasswordInternal(org.jasig.cas.authentication.principal.UsernamePasswordCredentials)
     */
    @Override
    protected boolean authenticateUsernamePasswordInternal(final UsernamePasswordCredentials credentials)
        throws AuthenticationException {
        final String username = credentials.getUsername();
        final String password = credentials.getPassword();
        JdbcTemplate template = new JdbcTemplate(getDataSource());

        try {
            // get user info by username, if no result found, auto throw IncorrectResultSizeDataAccessException
            UserInfo userInfo = (UserInfo) template.queryForObject(QUERY_USER_SQL, new String[]{username},
                new BeanPropertyRowMapper(UserInfo.class));
            // check user lock
            if (!"Y".equalsIgnoreCase(userInfo.getIsValid())) {
                // means user was locked
                throw new AccountLockedException();
            } else if (password.equals(userInfo.getPassword())) {
                // means correct username/password, login success return true
                return true;
            } else {
                // means wrong password, failure times +1
                int failureTimes = userInfo.getFailureTimes();
                if (++failureTimes >= Integer.valueOf(maxFailureTimes)) {
                    // touch max failure times, will lock this user
                    template.update(LOCK_USER_SQL, new Object[]{failureTimes, 'N', username});
                } else {
                    template.update(FAILURE_TRIGGER_SQL, new Object[]{failureTimes, username});
                }
                // throw wrong password exception
                throw new BadPasswordAuthenticationException();
            }
        } catch (final IncorrectResultSizeDataAccessException e) {
            // this means the username was not found.
            throw new UnknownUsernameAuthenticationException();
        }
    }

}

其中AccountLockedException是自定义的一个异常类,代码如下:
package com.cas;

import org.jasig.cas.authentication.handler.BadCredentialsAuthenticationException;

/**
 * @author
 * @Date
 */
public class AccountLockedException extends BadCredentialsAuthenticationException {
    /** Static instance of AccountLockedException. */
    public static final AccountLockedException ERROR = new AccountLockedException();
    /** Unique ID for serializing. */
    private static final long serialVersionUID = 6831383559080393480L;
    /** The code description of this exception. */
	/**这个自定义的异常码用来显示登录失败信息,对应的message配置在cas部署包的classes目录下的messages.properties文件里,支持国际化*/
    private static final String CODE = "error.authentication.credentials.bad.usernameorpassword.maxtrycount";

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

    /**
     * Constructor that allows for the chaining of exceptions. Defaults to the default code provided for this exception.
     *
     * @param throwable
     *            the chained exception.
     */
    public AccountLockedException(final Throwable throwable) {
        super(CODE, throwable);
    }

    /**
     * Constructor that allows for providing a custom error code for this class. Error codes are often used to resolve
     * exceptions into messages. Providing a custom error code allows the use of a different message.
     *
     * @param code
     *            the custom code to use with this exception.
     */
    public AccountLockedException(final String code) {
        super(code);
    }

    /**
     * Constructor that allows for chaining of exceptions and a custom error code.
     *
     * @param code
     *            the custom error code to use in message resolving.
     * @param throwable
     *            the chained exception.
     */
    public AccountLockedException(final String code, final Throwable throwable) {
        super(code, throwable);
    }
}

  • 3. 编译上述class,把生成的字节码文件放到cas的class path目录下:可以放到WEB-INF\classes目录下,或者打jar放到WEB-INF\lib目录下
  • 4. 修改cas部署包下的WEB-INF目录下的deployerConfigContext.xml
  • 调整authenticationManager类的描述,在authenticationHandlers list里面添加自定义的这个handler如下:
<bean id="authenticationManager"
	class="org.jasig.cas.authentication.AuthenticationManagerImpl">

	<property name="credentialsToPrincipalResolvers">
		<list>
			<bean
				class="org.jasig.cas.authentication.principal.UsernamePasswordCredentialsToPrincipalResolver" />

			<bean
				class="org.jasig.cas.authentication.principal.HttpBasedServiceCredentialsToPrincipalResolver" />
		</list>
	</property>

	<property name="authenticationHandlers">
		<list>
			<bean class="org.jasig.cas.authentication.handler.support.HttpBasedServiceCredentialsAuthenticationHandler"
				p:httpClient-ref="httpClient" />

			<bean class="com.cas.JdbcUsernamePasswordAuthHandlerImpl">
					<property name="dataSource" ref="dataSource" /><!--指定数据源-->
					<property name="passwordEncoder"><!--设置加密方式,这里要看数据库中存储的密码的加密方式是什么,要配置相应的加密器-->
						<bean class="org.jasig.cas.authentication.handler.DefaultPasswordEncoder">
							<constructor-arg value="MD5"/><!-- MD5加密方式-->
						</bean>
					</property>                       
					<property name="maxFailureTimes" value="3" /><!-- 这里对应JdbcUsernamePasswordAuthHandlerImpl类里的maxFailureTimes属性 -->
			</bean>
		</list>
	</property>
</bean>
<bean id="dataSource"
	class="org.springframework.jndi.JndiObjectFactoryBean">
	<property name="jndiName" value="java:/CAS" />
	<property name="lookupOnStartup" value="true"/>
	<property name="resourceRef" value="false" />
</bean>

  • 5. 客户化结束,重新部署CAS,3次登录失败之后,帐户自动被锁死。

总结:这个简单的客户化的过程主要依赖spring的jdbc包来实现数据访问,因此需要对spring以及org.springframework.jdbc.core这个包有所了解,用到的核心类是JdbcTemplate,这个类非常强大,提供了各种数据访问的方法,避免直接写JDBC管理连接、执行查询的繁琐,而又省去了配置hibernate或者JPA等第三方持久化框架的麻烦。
通过这个小例子,可以基本了解了Yale CAS的登录模块的实现。虽然Yale CAS真正强大之处在于它的SSO,以及超级复杂的文件配置(不过比起Spring Security的配置来,还是小巫见大巫啦)
分享到:
评论
1 楼 vincent_com 2011-04-18  
[color=red][/color]

相关推荐

    Yale CAS Server的部署及cas-java-client 3.2的应用

    CAS(Central Authentication Service,中央认证服务)是耶鲁大学开发的一个开源的身份验证框架,它为Web应用程序提供了单一登录(Single Sign-On,SSO)功能。这篇文章将详细介绍如何部署Yale CAS Server以及如何在...

    Yale CAS实现单点登陆的客户端和服务端源码

    Yale CAS实现单点登陆的客户端源码和服务端源码,客户端cas-client-3.1.10代码和cas-server-3.4.2.1代码

    Yale CAS SSO JAVA Client

    "Yale CAS SSO JAVA Client" 是一个专为Java应用程序设计的身份验证服务,它利用了耶鲁大学开发的中央认证服务(Central Authentication Service, CAS)。CAS是一种开放源代码的单点登录(Single Sign-On, SSO)框架...

    cas-client-3.3.3-release和cas-server-4.2.1-release下载

    CAS(Central Authentication Service)是 Yale 大学开发的一个开源项目,它提供了实现SSO的标准框架。CAS 通过统一的身份验证接口,简化了用户对多个应用系统的身份验证过程,提高了用户体验并增强了安全性。 在这...

    Yale CAS最佳实践.rar

    **Yale CAS(Central Authentication Service)是耶鲁大学开发的一款基于Web的身份验证系统,它允许用户通过单一登录(Single Sign-On, SSO)访问多个应用系统。本篇将详细探讨Yale CAS的最佳实践,包括环境准备、...

    cas-server-webapp

    CAS(Central Authentication Service) 是 Yale 大学发起的一个开源项目,据统计,大概每 10 个采用开源构建 Web SSO 的 Java 项目,就有 8 个使用 CAS 。

    yale-cas服务器端深度定制

    【标题】"Yale CAS服务器端深度定制"主要涉及到的是CAS(Central Authentication Service)系统,这是一个基于Java开发的开源身份验证框架,由耶鲁大学开发并广泛应用于各个机构的单点登录(Single Sign-On,SSO)...

    Yale CAS SSO DotNet Client

    "Yale CAS SSO DotNet Client" 是一个专为.NET框架设计的客户端库,用于集成耶鲁大学(Yale)的中央认证服务(Central Authentication Service, CAS)。CAS是一种开源的身份验证协议,它允许用户通过单一登录...

    Archives-at-Yale-EAD3-master.zip

    总之,"Archives-at-Yale-EAD3-master.zip" 提供了一个深入了解和实践EAD3的平台,对于档案管理者、图书馆员以及数字人文研究者来说,这是一个宝贵的资源,有助于提升他们对档案描述标准的理解和运用。通过学习和...

    Face-Recognition-on-Yale-Face-Dataset-master.zip_Face/On_Yale Fa

    综上所述,"Face-Recognition-on-Yale-Face-Dataset-master.zip"项目提供了一个全面的人脸识别解决方案,涵盖了从数据预处理到模型训练,再到性能评估的全过程。通过使用PCA和SVM这两种强大的工具,该项目实现了在...

    cas-client-2.0.11.zip_cas client_cas-clie_cas-client-2._java CAS

    8. **Yale大学**:CAS最初由耶鲁大学开发并开源,现在已成为一个广泛使用的标准,有许多社区维护的实现,如Apereo CAS,它提供了更多的特性和扩展。 通过理解和应用这些知识点,开发者可以有效地利用CAS客户端...

    耶鲁CasServer单点登录教程

    Yale Central Authentication Service (CAS) 是一个开源的身份验证框架,由耶鲁大学开发,主要用于实现单点登录(Single Sign-On, SSO)。SSO允许用户在一个系统上登录后,无需再次认证即可访问其他多个相互信任的...

    用YALE -CAS实现SSO

    Yale CAS(Central Authentication Service)是由耶鲁大学开发的一个开源项目,专门用于实现SSO功能。它是一个平台无关的解决方案,易于理解和部署,并且支持代理功能,这意味着它可以与各种不同的应用程序和服务...

    yale-cas 与 shiro进行整合

    CAS是由耶鲁大学开发的一个开放源码的单一登录(Single Sign-On, SSO)系统,旨在简化用户身份验证过程,让用户只需一次登录就能访问多个应用。而Apache Shiro则是一个全面且易用的Java安全框架,涵盖了身份验证、...

    Weblogic使用YALE(耶鲁)CAS实现SSO单点登录 的方法.doc

    Yale CAS 是耶鲁大学开发的一种开源的单点登录(SSO)解决方案,提供了一个通用的身份验证框架,允许用户使用单个身份验证来访问多个应用程序。CAS 服务器充当着身份验证服务器的角色,负责验证用户的身份,生成 ...

    cas-client-3.1.12-release.zip

    CAS(Central Authentication Service)是 Yale 大学开发的一个开源项目,主要用于实现单点登录(Single Sign-On, SSO)。它是一个基于Web的认证协议,旨在简化用户对多个应用系统的访问管理,通过一次登录即可访问...

    edu.yale.its.tp.cas.client.IContextInit修复工具.rar

    软件介绍: ...下载后先解压,然后将sso-client-java-7.0.8.jar文件复制到lib里面,鼠标单击右键在属性一栏的弹出框内添加该jar包即可解决解决普元EOS报错问题:edu.yale.its.tp.cas.client.IContextInit 

Global site tag (gtag.js) - Google Analytics