Cas(06)基于数据库的认证
基于数据库的认证 Cas Server自身已经为我们实现了几种基于JDBC的AuthenticationHandler实现,但它们不包含在Cas Server的核心包里面,而是包含在cas-server-support-jdbc中,如果我们要使用Cas Server已经实现好的基于JDBC的AuthenticationHandler,我们必
基于数据库的认证
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.casgroupId>
artifactId>cas-server-support-jdbcartifactId>
version>${cas.version}version>
scope>runtimescope>
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>
...
beanclass="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(finalUsernamePasswordCredentials 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 length
推荐阅读
-
Cas(06)基于数据库的认证
-
PHP数据库操作之基于Mysqli的数据库操作类库_PHP教程
-
在OracleLinux5.11上构建基于LVM的裸设备的Oracle10g数据库_PHP教程
-
基于文件的网页身份认证
-
基于数据库锁实现springtask的集群
-
基于数据库锁实现springtask的集群
-
基于IP的简单网站访问量统计(已更新版优化SQL数据库)
-
基于数据库、php、ajax的 3级地区联动
-
基于Android系统的数据库类设计 博客分类: 编程 Android系统数据库类设计SQLiteSQLiteOpenHelper
-
PHP基于单例模式实现的数据库操作基类,php例模式数据库_PHP教程