1、问题
AuthenticationSuccessHandler处理中的Authentication是什么,与传入AuthenticationManager#authenticate(Authentication authentication)中的 Authentication是一样的吗
2、分析
UsernameAuthenticationFilter中调用AuthenticationManager#authenticate,其实调用的是DaoAuthenticationProvider的authenticate,在其父类AbstractUserDetailsAuthenticationProvider中定义了处理模板。其处理代码如下
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
String username = determineUsername(authentication);
boolean cacheWasUsed = true;
UserDetails user = this.userCache.getUserFromCache(username);
if (user == null) {
cacheWasUsed = false;
user = retrieveUser(username, (UsernamePasswordAuthenticationToken) authentication);
}
this.preAuthenticationChecks.check(user);
additionalAuthenticationChecks(user, (UsernamePasswordAuthenticationToken) authentication);
this.postAuthenticationChecks.check(user);
if (!cacheWasUsed) {
this.userCache.putUserInCache(user);
}
Object principalToReturn = user;
if (this.forcePrincipalAsString) {
principalToReturn = user.getUsername();
}
return createSuccessAuthentication(principalToReturn, authentication, user);
}
principalToReturn为retrieveUser返回的。DaoAuthenticationProvider的retrieveUser是通过UserDetailsService#loadUserByUserName得到UserDetails。
protected final UserDetails retrieveUser(String username, UsernamePasswordAuthenticationToken authentication)
throws AuthenticationException {
prepareTimingAttackProtection();
UserDetails loadedUser = this.getUserDetailsService().loadUserByUsername(username);
if (loadedUser == null) {
throw new InternalAuthenticationServiceException(
"UserDetailsService returned null, which is an interface contract violation");
}
return loadedUser;
}
}
然后创建新的Authentication,即以UserDetails作为principal。
protected Authentication createSuccessAuthentication(Object principal, Authentication authentication,
UserDetails user) {
// Ensure we return the original credentials the user supplied,
// so subsequent attempts are successful even with encoded passwords.
// Also ensure we return the original getDetails(), so that future
// authentication events after cache expiry contain the details
UsernamePasswordAuthenticationToken result = UsernamePasswordAuthenticationToken.authenticated(principal,
authentication.getCredentials(), this.authoritiesMapper.mapAuthorities(user.getAuthorities()));
result.setDetails(authentication.getDetails());
this.logger.debug("Authenticated user");
return result;
}
3、结论
AuthenticationSuccessHandler中的 authentication与AuthenticationManager#authenticate传入的不一样,AuthenticationSuccessHandler中的authentication是由UserDetails作为principal,AuthenticationManager#authenticate传入的authentication的credentials作为新authentication的credentials