CAS认证流程3:验证用户信息 .
/>
????? ??????? ? <property name="sql"value="select USER_PASSWORD fromt_sso_userinfo where USER_NAME=? " />
????? ???????? </bean>?
????? ???????
??????? </list>
????? </property>
?? </bean>
?我们可以看到,在manager中,主要有两个list的属性:credentialsToPrincipalResolvers和authenticationHandlers
其中authenticationHandlers list主要是用来做认证用的。该list中所有的bean都需要实现AuthenticationHandler接口中的authenticate方法。用户提交认证请求之后,要满足该list中任意认证的条件才算是认证成功。每一个bean都可以配置自己的验证方式。所以,对于有多个认证方式的应用的时候,在这里自行组装认证条件就可以。
credentialsToPrincipalResolverslist属性主要是在验证成功之后,将用户属性提取出来。并传递到接入系统中。如果用户数据存储在存在多个数据源中,则在这里可以写多个属性提取器,分别将用户的属性提取出来,然后处理后传递给客户端。
下面我们就源码进行分析。查看AuthenticationManagerImpl.authenticateAndObtainPrincipal方法:
?
//通过验证器链对用户提供的认证信息进行认证
??????? for (final AuthenticationHandlerauthenticationHandler : this.authenticationHandlers) {
??????????? if(authenticationHandler.supports(credentials)) {
??????????????? foundSupported = true;
??????????????? if(!authenticationHandler.authenticate(credentials)) {
??????????????????? 。。。。。
??????????????? } else {
?????????????????? 。。。。。
??????????????????? authenticatedClass =authenticationHandler;
??????????????????? authenticated = true;
??????????????????? break;
??????????????? }
??????????? }
??????? }
这里可以看到,就是对authenticationHandlers 进行遍历,如果通过认证,则break。
foundSupported = false;
??????? //认证成功之后,通过认证信息,提取出用户的完整信息
??????? for (finalCredentialsToPrincipalResolver credentialsToPrincipalResolver : this.credentialsToPrincipalResolvers) {
??????????? if(credentialsToPrincipalResolver.supports(credentials)) {
??????????????? final Principal principal =credentialsToPrincipalResolver
???????????????????.resolvePrincipal(credentials);
??????????????? foundSupported = true;
??????????????? if (principal != null) {
??????????????????? return new Pair<AuthenticationHandler,Principal>(authenticatedClass,principal);
??????????????? }
??????????? }
???????}
?
这里对credentialsToPrincipalResolvers进行解析,一旦获取到用户的属性,则构建了一个新的Pair对象,该对象中有认证的类和用户属性。
下面,我们就深入org.jasig.cas.adaptors.jdbc.QueryDatabaseAuthenticationHandler看一下该类是如何对用户进行认证的。
这里,我对这个类简单看一下,credentials是对认证请求的简单封装。当然可以获取到用户名和密码。然后将密码进行加密之后,同数据库查询的结果进行比对。
final Stringusername = 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);
??????????? returndbPassword.equals(encryptedPassword);
??????? } catch (finalIncorrectResultSizeDataAccessException e) {
??????????? // this means the username was notfound.
??????????? return false;
??????? }
CAS中,对于数据库的操作主要都是使用spring的JdbcTemplate 来操作的。这里也不例外。
?
这里的业务逻辑比较简单。在回头看看这里的实现。他将能分离出来的组件全都独立出来。比如说密码加密算法。数据源,查询语句等。任何组件的更改不会对其他的组件产生影响。这就是面向对象的好处,这就是使用spring ioc的好处。