项目使用Yale CAS+Spring Security实现单点登录以及权限验证
需要对Yale CAS的登录模块进行一下改动,如果用户输入帐号密码失败次数超过3次的时候,要把帐号锁定,这样要等管理员解锁以后才可以再次登录这个帐号。
Yale CAS的登录是个典型的密码验证模块,不能提供上述需求,这就需要对CAS的登录部分做些改动
(暂且不考虑这个需求是不是合理,单纯从技术角度来实现这个需求)
具体分析如下:
- 1. 一个帐户需要多记录两个属性:密码输错的次数以及帐户是否可登录;
- 2. 用户提交登录申请的时候,先检验该帐户是否可登录,如果是,继续进行下面的,如果否,返回登录失败信息;
- 3. 校验用户帐户和密码,如果密码正确,返回登录成功,如果密码错误,继续进行下面的;
- 4. 该帐户的密码输错次数加1,并比较现在的输错次数是否小于3(可配置),如果是,返回登录失败信息,如果否,继续进行下面的;
- 5. 将帐户是否可登录属性设置为否,返回登录失败信息。
综合上述分析,实现如下:
- 1. 数据库中设计帐户信息时加两个字段failureTimes和isValid来记录错误登录次数和是否被锁定
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的配置来,还是小巫见大巫啦)
分享到:
相关推荐
CAS(Central Authentication Service,中央认证服务)是耶鲁大学开发的一个开源的身份验证框架,它为Web应用程序提供了单一登录(Single Sign-On,SSO)功能。这篇文章将详细介绍如何部署Yale CAS Server以及如何在...
Yale CAS实现单点登陆的客户端源码和服务端源码,客户端cas-client-3.1.10代码和cas-server-3.4.2.1代码
"Yale CAS SSO JAVA Client" 是一个专为Java应用程序设计的身份验证服务,它利用了耶鲁大学开发的中央认证服务(Central Authentication Service, CAS)。CAS是一种开放源代码的单点登录(Single Sign-On, SSO)框架...
CAS(Central Authentication Service)是 Yale 大学开发的一个开源项目,它提供了实现SSO的标准框架。CAS 通过统一的身份验证接口,简化了用户对多个应用系统的身份验证过程,提高了用户体验并增强了安全性。 在这...
**Yale CAS(Central Authentication Service)是耶鲁大学开发的一款基于Web的身份验证系统,它允许用户通过单一登录(Single Sign-On, SSO)访问多个应用系统。本篇将详细探讨Yale CAS的最佳实践,包括环境准备、...
CAS(Central Authentication Service) 是 Yale 大学发起的一个开源项目,据统计,大概每 10 个采用开源构建 Web SSO 的 Java 项目,就有 8 个使用 CAS 。
【标题】"Yale CAS服务器端深度定制"主要涉及到的是CAS(Central Authentication Service)系统,这是一个基于Java开发的开源身份验证框架,由耶鲁大学开发并广泛应用于各个机构的单点登录(Single Sign-On,SSO)...
"Yale CAS SSO DotNet Client" 是一个专为.NET框架设计的客户端库,用于集成耶鲁大学(Yale)的中央认证服务(Central Authentication Service, CAS)。CAS是一种开源的身份验证协议,它允许用户通过单一登录...
总之,"Archives-at-Yale-EAD3-master.zip" 提供了一个深入了解和实践EAD3的平台,对于档案管理者、图书馆员以及数字人文研究者来说,这是一个宝贵的资源,有助于提升他们对档案描述标准的理解和运用。通过学习和...
综上所述,"Face-Recognition-on-Yale-Face-Dataset-master.zip"项目提供了一个全面的人脸识别解决方案,涵盖了从数据预处理到模型训练,再到性能评估的全过程。通过使用PCA和SVM这两种强大的工具,该项目实现了在...
8. **Yale大学**:CAS最初由耶鲁大学开发并开源,现在已成为一个广泛使用的标准,有许多社区维护的实现,如Apereo CAS,它提供了更多的特性和扩展。 通过理解和应用这些知识点,开发者可以有效地利用CAS客户端...
Yale Central Authentication Service (CAS) 是一个开源的身份验证框架,由耶鲁大学开发,主要用于实现单点登录(Single Sign-On, SSO)。SSO允许用户在一个系统上登录后,无需再次认证即可访问其他多个相互信任的...
Yale CAS(Central Authentication Service)是由耶鲁大学开发的一个开源项目,专门用于实现SSO功能。它是一个平台无关的解决方案,易于理解和部署,并且支持代理功能,这意味着它可以与各种不同的应用程序和服务...
CAS是由耶鲁大学开发的一个开放源码的单一登录(Single Sign-On, SSO)系统,旨在简化用户身份验证过程,让用户只需一次登录就能访问多个应用。而Apache Shiro则是一个全面且易用的Java安全框架,涵盖了身份验证、...
Yale CAS 是耶鲁大学开发的一种开源的单点登录(SSO)解决方案,提供了一个通用的身份验证框架,允许用户使用单个身份验证来访问多个应用程序。CAS 服务器充当着身份验证服务器的角色,负责验证用户的身份,生成 ...
CAS(Central Authentication Service)是 Yale 大学开发的一个开源项目,主要用于实现单点登录(Single Sign-On, SSO)。它是一个基于Web的认证协议,旨在简化用户对多个应用系统的访问管理,通过一次登录即可访问...
软件介绍: ...下载后先解压,然后将sso-client-java-7.0.8.jar文件复制到lib里面,鼠标单击右键在属性一栏的弹出框内添加该jar包即可解决解决普元EOS报错问题:edu.yale.its.tp.cas.client.IContextInit