基于数据库的认证
目录
1.1 BindModeSearchDatabaseAuthenticationHandler
1.2 QueryDatabaseAuthenticationHandler
1.2.1 PrefixSuffixPrincipalNameTransformer
1.2.2 DefaultPasswordEncoder
1.3 SearchModeSearchDatabaseAuthenticationHandler
Cas Server自身已经为我们实现了几种基于JDBC的AuthenticationHandler实现,但它们不包含在Cas Server的核心包里面,而是包含在cas-server-support-jdbc中,如果我们要使用Cas Server已经实现好的基于JDBC的AuthenticationHandler,我们必须先将cas-server-support-jdbc对应的jar包、相关数据库的驱动,以及所需要使用的数据源实现等jar包加入Cas Server的类路径中。如果是基于Maven的war覆盖机制来修改Cas Server的配置文件,则我们可以在自己的Maven项目的依赖中加入如下项(对应的驱动就没贴出来了)。
<dependency>
<groupId>org.jasig.cas</groupId>
<artifactId>cas-server-support-jdbc</artifactId>
<version>${cas.version}</version>
<scope>runtime</scope>
</dependency>
Cas Server默认已经实现好的基于JDBC的AuthenticationHandler有三个,它们都继承自AbstractJdbcUsernamePasswordAuthenticationHandler,而且在认证过程中都需要一个DataSource。下面来对它们做一个简要的介绍。
1.1 BindModeSearchDatabaseAuthenticationHandler
BindModeSearchDatabaseAuthenticationHandler将试图以传入的用户名和密码从配置的DataSource中建立一个连接,如果连接成功,则表示认证成功,否则就是认证失败。以下是BindModeSearchDatabaseAuthenticationHandler源码的一段主要代码,通过它我们可以明显的看清其逻辑:
protected final boolean authenticateUsernamePasswordInternal(
final UsernamePasswordCredentials credentials)
throws AuthenticationException {
final String username = credentials.getUsername();
final String password = credentials.getPassword();
try {
final Connection c = this.getDataSource()
.getConnection(username, password);
DataSourceUtils.releaseConnection(c, this.getDataSource());
returntrue;
} catch (final SQLException e) {
returnfalse;
}
}
当然,这种实现也需要你的DataSource支持getConnection(user,password)才行,否则将返回false。dbcp的BasicDataSource的不支持的,而c3p0的ComboPooledDataSource支持。
以下是一个使用BindModeSearchDatabaseAuthenticationHandler的配置示例:
<bean id="authenticationManager"
class="org.jasig.cas.authentication.AuthenticationManagerImpl">
...
<property name="authenticationHandlers">
<list>
...
<bean class="org.jasig.cas.adaptors.jdbc.BindModeSearchDatabaseAuthenticationHandler">
<property name="dataSource" ref="dataSource"/>
</bean>
...
</list>
</property>
...
</bean>
1.2 QueryDatabaseAuthenticationHandler
使用QueryDatabaseAuthenticationHandler需要我们指定一个SQL,该SQL将接收一个用户名作为查询条件,然后返回对应的密码。该SQL将被QueryDatabaseAuthenticationHandler用来通过传入的用户名查询对应的密码,如果存在则将查询的密码与查询出来的密码进行匹配,匹配结果将作为认证结果。如果对应的用户名不存在也将返回false。
以下是QueryDatabaseAuthenticationHandler的一段主要代码:
protected final boolean authenticateUsernamePasswordInternal(final UsernamePasswordCredentials credentials) throws AuthenticationException {
final String username = getPrincipalNameTransformer().transform(credentials.getUsername());
final String password = credentials.getPassword();
final String encryptedPassword = this.getPasswordEncoder().encode(
password);
try {
final String dbPassword = getJdbcTemplate().queryForObject(this.sql, String.class, username);
return dbPassword.equals(encryptedPassword);
} catch (final IncorrectResultSizeDataAccessException e) {
// this means the username was not found.
returnfalse;
}
}
上面的逻辑非常明显。此外,如你所见,QueryDatabaseAuthenticationHandler使用的用户名会经过PrincipalNameTransformer进行转换,而密码会经过PasswordEncoder进行编码。Cas Server中基于JDBC的AuthenticationHandler实现中使用到的PrincipalNameTransformer默认是不进行任何转换的NoOpPrincipalNameTransformer,而默认使用的PasswordEncoder也是不会经过任何编码的PlainTextPasswordEncoder。当然了,cas-server-jdbc-support对它们也有另外两种支持,即PrefixSuffixPrincipalNameTransformer和DefaultPasswordEncoder。
1.2.1 PrefixSuffixPrincipalNameTransformer
PrefixSuffixPrincipalNameTransformer的作用很明显,如其名称所描述的那样,其在转换时会将用户名加上指定的前缀和后缀。所以用户在使用的时候需要指定prefix和suffix两个属性,默认是空。
1.2.2 DefaultPasswordEncoder
DefaultPasswordEncoder底层使用的是标准Java类库中的MessageDigest进行加密的,其支持MD5、SHA等加密算法。在使用时需要通过构造参数encodingAlgorithm来指定使用的加密算法,可以使用characterEncoding属性注入来指定获取字节时使用的编码,不指定则使用默认编码。以下是DefaultPasswordEncoder的源码,其展示了DefaultPasswordEncoder的加密逻辑。
public final class DefaultPasswordEncoder implements PasswordEncoder {
privatestaticfinalchar[] HEX_DIGITS = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
@NotNull
privatefinal String encodingAlgorithm;
private String characterEncoding;
public DefaultPasswordEncoder(final String encodingAlgorithm) {
this.encodingAlgorithm = encodingAlgorithm;
}
public String encode(final String password) {
if (password == null) {
returnnull;
}
try {
MessageDigest messageDigest = MessageDigest
.getInstance(this.encodingAlgorithm);
if (StringUtils.hasText(this.characterEncoding)) {
messageDigest.update(password.getBytes(this.characterEncoding));
} else {
messageDigest.update(password.getBytes());
}
finalbyte[] digest = messageDigest.digest();
return getFormattedText(digest);
} catch (final NoSuchAlgorithmException e) {
thrownew SecurityException(e);
} catch (final UnsupportedEncodingException e) {
thrownew RuntimeException(e);
}
}
/**
* Takes the raw bytes from the digest and formats them correct.
*
* @param bytes the raw bytes from the digest.
* @return the formatted bytes.
*/
private String getFormattedText(byte[] bytes) {
final StringBuilder buf = new StringBuilder(bytes.length * 2);
for (int j = 0; j < bytes.length; j++) {
buf.append(HEX_DIGITS[(bytes[j] >> 4) & 0x0f]);
buf.append(HEX_DIGITS[bytes[j] & 0x0f]);
}
return buf.toString();
}
publicfinalvoid setCharacterEncoding(final String characterEncoding) {
this.characterEncoding = characterEncoding;
}
}
如果在认证时需要使用DefaultPasswordEncoder,则需要确保数据库中保存的密码的加密方式和DefaultPasswordEncoder的加密算法及逻辑是一致的。如果这些都不能满足你的需求,则用户可以实现自己的PrincipalNameTransformer和PasswordEncoder。
以下是一个配置使用QueryDatabaseAuthenticationHandler进行认证,且使用DefaultPasswordEncoder对密码进行MD5加密的示例:
<bean id="authenticationManager"
class="org.jasig.cas.authentication.AuthenticationManagerImpl">
...
<property name="authenticationHandlers">
<list>
...
<bean class="org.jasig.cas.adaptors.jdbc.QueryDatabaseAuthenticationHandler">
<property name="dataSource" ref="dataSource"/>
<property name="passwordEncoder" ref="passwordEncoder"/>
<property name="sql" value="select password from t_user where username = ?"/>
</bean>
...
</list>
</property>
...
</bean>
<bean id="passwordEncoder" class="org.jasig.cas.authentication.handler.DefaultPasswordEncoder">
<constructor-arg value="MD5"/><!-- 加密算法 -->
</bean>
1.3 SearchModeSearchDatabaseAuthenticationHandler
SearchModeSearchDatabaseAuthenticationHandler的主要逻辑是将传入的用户名和密码作为条件从指定的表中进行查询,如果对应记录存在则表示认证通过。使用该AuthenticationHandler时需要我们指定查询时使用的表名(tableUsers)、用户名对应的字段名(fieldUser)和密码对应的字段名(fieldPassword)。此外,还可以选择性的使用PrincipalNameTransformer和PasswordEncoder。以下是SearchModeSearchDatabaseAuthenticationHandler源码中的一段主要代码:
private static final String SQL_PREFIX = "Select count('x') from ";
@NotNull
private String fieldUser;
@NotNull
private String fieldPassword;
@NotNull
private String tableUsers;
private String sql;
protectedfinalboolean authenticateUsernamePasswordInternal(final UsernamePasswordCredentials credentials) throws AuthenticationException {
final String transformedUsername = getPrincipalNameTransformer().transform(credentials.getUsername());
final String encyptedPassword = getPasswordEncoder().encode(credentials.getPassword());
finalint count = getJdbcTemplate().queryForInt(this.sql,
transformedUsername, encyptedPassword);
return count > 0;
}
publicvoid afterPropertiesSet() throws Exception {
this.sql = SQL_PREFIX + this.tableUsers + " Where " + this.fieldUser
+ " = ? And " + this.fieldPassword + " = ?";
}
以下是一个使用SearchModeSearchDatabaseAuthenticationHandler的配置示例:
<bean id="authenticationManager"
class="org.jasig.cas.authentication.AuthenticationManagerImpl">
...
<property name="authenticationHandlers">
<list>
...
<bean class="org.jasig.cas.adaptors.jdbc.SearchModeSearchDatabaseAuthenticationHandler">
<property name="dataSource" ref="dataSource"/>
<property name="passwordEncoder" ref="passwordEncoder"/>
<property name="tableUsers" value="t_user"/><!-- 指定从哪个用户表查询用户信息 -->
<property name="fieldUser" value="username"/><!-- 指定用户名在用户表对应的字段名 -->
<property name="fieldPassword" value="password"/><!-- 指定密码在用户表对应的字段名 -->
</bean>
...
</list>
</property>
...
</bean>
至此,cas-server-support-jdbc中支持JDBC的三个AuthenticationHandler就讲完了。如果用户觉得它们都不能满足你的要求,则还可以选择使用自己实现的AuthenticationHandler。至于其它认证方式,请参考官方文档。
(注:本文是基于cas 3.5.2所写)
(注:原创文章,转载请注明出处。原文地址:http://elim.iteye.com/blog/2142616)
相关推荐
假设我们有两个Web应用程序——`test1`和`test2`,这两个应用均集成了CAS客户端。其中,`test1`运行在`http://www.zhuowei.com:8081/`上,而`test2`则运行在`http://www.zhuowei.com:8082/`。同时,CAS服务器运行在`...
**JASIG CAS 3 学习笔记 1 —— 开始之旅** JASIG CAS(Central Authentication Service)是一款开源的身份验证系统,广泛应用于多应用系统中的单点登录(Single Sign-On, SSO)。CAS 3 是其第三个主要版本,提供了...
6. **票证管理**:CAS Server使用两种主要类型的票证——登录票证(Ticket Granting Ticket,TGT)和服务票证(Service Ticket)。TGT是在用户成功登录后生成的,用于后续的SSO请求,而服务票证是一次性的,每次访问...
本文主要分析两种常见的SSO实现框架——JOSSO(Java Open Single Sign-On)和CAS(Central Authentication Service)。 JOSSO是一个基于Java和J2EE的开源SSO框架,其主要特点如下: 1. 100% Java实现,利用了JAAS...
本文将深入探讨SpringBoot-Security的两种配置方式——使用Config类和使用注解,并讨论如何与数据库交互来管理用户。 ### 一、Config类配置 1. **创建SecurityConfig类**:首先,我们需要创建一个继承自`...
- **用户认证逻辑**:CAS服务器的用户认证实现,可能包括数据库查询、LDAP集成等。 - **票据管理**:如何创建、存储和验证票据,确保安全性。 五、工具支持 在实际开发中,我们可以使用各种开源工具和库来简化SSO...
在ORL和CAS-PEAL两个人脸数据库上进行的测试表明,该方法在降低特征维度的同时,相较于传统基于Gabor的方法,如局部Gabor二进制模式(LGBP)和局部Gabor异或模式(LGXP),具有更优异的识别性能。这一结果充分说明了...
- **案例分析**:提供几个典型应用场景下的项目示例,如一个简单的记事本程序、一个基于数据库的库存管理系统等。 - **代码实现**:详细介绍这些项目的实现细节,包括关键代码片段和调试技巧。 - **最佳实践**:...
- **数据库表结构**:设计用于存储用户和权限信息的数据库表结构,确保数据模型能够满足安全需求。 - **自定义数据库表结构** - **自定义表结构**:根据项目的具体需求,设计更为灵活和可扩展的表结构。 - **初始...
实验结果表明,WTMPCA方法在ORL和CAS-PEAL-R1两个常用人脸数据库上的识别率达到了96%,相比传统的2D-PCA,识别性能显著提升。此外,该算法对光照条件的变化以及脸部表情的微小改变具有良好的鲁棒性,能够在实际应用...
7.4. 使用其他过滤器 —— 基于框架 8. 核心安全过滤器 8.1. FilterSecurityInterceptor 8.2. ExceptionTranslationFilter 8.2.1. AuthenticationEntryPoint 8.2.2. AccessDeniedHandler 8.3. ...
- 它可以保护任何应用——从简单的应用到复杂的多层企业级应用。 #### 二、基础篇 ##### 1. 一个简单的 HelloWorld 示例 - **配置过滤器**: Spring Security 提供了一组预定义的过滤器,可以轻松地在应用中集成...
《基于Spring Boot、JPA、JWT与Vue的后台管理系统——eladmin深度解析》 eladmin是一个功能丰富的后台管理系统,它采用最新的技术栈构建,包括Spring Boot 2.6.4、Spring Boot Jpa、JWT(JSON Web Token)、Spring ...
5. **用户认证**:支持两种认证方式——Cookie和JWT(JSON Web Tokens)。 #### 三、技术栈 - **Go语言版本**:go1.13.3及以上版本。 - **数据库**:MySQL 5.7。 - **缓存**:Redis 3.0。 - **依赖包**: - `...