while (iter.hasNext()) {
AuthenticationProvider provider = (AuthenticationProvider) iter.next();
if (provider.supports(toTest)) {
logger.debug("Authentication attempt using " + provider.getClass().getName());
//这个result包含了验证中得到的结果信息
Authentication result = null;
try {//这里是provider进行验证处理的过程
result = provider.authenticate(authentication);
sessionController.checkAuthenticationAllowed(result);
} catch (AuthenticationException ae) {
lastException = ae;
result = null;
}
if (result != null) {
sessionController.registerSuccessfulAuthentication(result);
publishEvent(new AuthenticationSuccessEvent(result));
return result;
}
}
}
if (lastException == null) {
lastException = new ProviderNotFoundException(messages.getMessage("ProviderManager.providerNotFound",
new Object[] {toTest.getName()}, "No AuthenticationProvider found for {0}"));
}
if (event != null) {
publishEvent(event);
} else {
if (logger.isDebugEnabled()) {
logger.debug("No event was found for the exception " + lastException.getClass().getName());
}
}
// Throw the exception
throw lastException;
}
[/code]
我们下面看看在DaoAuthenticationProvider是怎样从数据库中取出对应的验证信息进行用户验证的,在它的基类AbstractUserDetailsAuthenticationProvider定义了验证的处理模板:
[code]
public Authentication authenticate(Authentication authentication)
throws AuthenticationException {
Assert.isInstanceOf(UsernamePasswordAuthenticationToken.class, authentication,
messages.getMessage("AbstractUserDetailsAuthenticationProvider.onlySupports",
"Only UsernamePasswordAuthenticationToken is supported"));
try {//这里是调用UserDetailService去取用户数据库里信息的地方
user = retrieveUser(username, (UsernamePasswordAuthenticationToken) authentication);
} catch (UsernameNotFoundException notFound) {
if (hideUserNotFoundExceptions) {
throw new BadCredentialsException(messages.getMessage(
"AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials"));
} else {
throw notFound;
}
}
Assert.notNull(user, "retrieveUser returned null - a violation of the interface contract");
}
if (!user.isAccountNonLocked()) {
throw new LockedException(messages.getMessage("AbstractUserDetailsAuthenticationProvider.locked",
"User account is locked"));
}
if (!user.isEnabled()) {
throw new DisabledException(messages.getMessage("AbstractUserDetailsAuthenticationProvider.disabled",
"User is disabled"));
}
if (!user.isAccountNonExpired()) {
throw new AccountExpiredException(messages.getMessage("AbstractUserDetailsAuthenticationProvider.expired",
"User account has expired"));
}
// This check must come here, as we don't want to tell users
// about account status unless they presented the correct credentials
try {//这里是验证过程,在retrieveUser中从数据库中得到用户的信息,在additionalAuthenticationChecks中进行对比用户输入和服务器端的用户信息
//如果验证通过,那么构造一个Authentication对象来让以后的授权使用,如果验证不通过,直接抛出异常结束鉴权过程
additionalAuthenticationChecks(user, (UsernamePasswordAuthenticationToken) authentication);
} catch (AuthenticationException exception) {
if (cacheWasUsed) {
// There was a problem, so try again after checking
// we're using latest data (ie not from the cache)
cacheWasUsed = false;
user = retrieveUser(username, (UsernamePasswordAuthenticationToken) authentication);
additionalAuthenticationChecks(user, (UsernamePasswordAuthenticationToken) authentication);
} else {
throw exception;
}
}
if (!user.isCredentialsNonExpired()) {
throw new CredentialsExpiredException(messages.getMessage(
"AbstractUserDetailsAuthenticationProvider.credentialsExpired", "User credentials have expired"));
}
//根据前面的缓存结果决定是不是要把当前的用户信息存入缓存以供下次验证使用
if (!cacheWasUsed) {
this.userCache.putUserInCache(user);
}
if (loadedUser == null) {
throw new AuthenticationServiceException(
"UserDetailsService returned null, which is an interface contract violation");
}
return loadedUser;
}
[/code]
下面我们重点分析一下JdbcDaoImp这个类来看看具体是怎样从数据库中得到用户信息的:
[code]
public class JdbcDaoImpl extends JdbcDaoSupport implements UserDetailsService {
//~ Static fields/initializers =====================================================================================
//这里是预定义好的对查询语句,对应于默认的数据库表结构,也可以自己定义查询语句对应特定的用户数据库验证表的设计
public static final String DEF_USERS_BY_USERNAME_QUERY =
"SELECT username,password,enabled FROM users WHERE username = ?";
public static final String DEF_AUTHORITIES_BY_USERNAME_QUERY =
"SELECT username,authority FROM authorities WHERE username = ?";
/**
* Extension point to allow other MappingSqlQuery objects to be substituted in a subclass
*/
protected void initMappingSqlQueries() {
this.usersByUsernameMapping = new UsersByUsernameMapping(getDataSource());
this.authoritiesByUsernameMapping = new AuthoritiesByUsernameMapping(getDataSource());
}
public boolean isUsernameBasedPrimaryKey() {
return usernameBasedPrimaryKey;
}
//这里是取得数据库用户信息的具体过程
public UserDetails loadUserByUsername(String username)
throws UsernameNotFoundException, DataAccessException {
//根据用户名在用户表中得到用户信息,包括用户名,密码和用户是否有效的信息
List users = usersByUsernameMapping.execute(username);
if (users.size() == 0) {
throw new UsernameNotFoundException("User not found");
}
//取集合中的第一个作为有效的用户对象
UserDetails user = (UserDetails) users.get(0); // contains no GrantedAuthority[]
//这里在权限表中去取得用户的权限信息,同样的返回一个权限集合对应于这个用户
List dbAuths = authoritiesByUsernameMapping.execute(user.getUsername());
if (dbAuths.size() == 0) {
throw new UsernameNotFoundException("User has no GrantedAuthority");
}
//这里根据得到的权限集合来配置返回的User对象供以后使用
GrantedAuthority[] arrayAuths = (GrantedAuthority[]) dbAuths.toArray(new GrantedAuthority[dbAuths.size()]);
String returnUsername = user.getUsername();
if (!usernameBasedPrimaryKey) {
returnUsername = username;
}
return new User(returnUsername, user.getPassword(), user.isEnabled(), true, true, true, arrayAuths);
}
public void setAuthoritiesByUsernameQuery(String queryString) {
authoritiesByUsernameQuery = queryString;
}
public void setRolePrefix(String rolePrefix) {
this.rolePrefix = rolePrefix;
}
public void setUsernameBasedPrimaryKey(boolean usernameBasedPrimaryKey) {
this.usernameBasedPrimaryKey = usernameBasedPrimaryKey;
}
public void setUsersByUsernameQuery(String usersByUsernameQueryString) {
this.usersByUsernameQuery = usersByUsernameQueryString;
}