认证和授权是安全管理的两个基本功能。本文将介绍下Spring Security 3.1的认证机制。整个认证过程所涉及到的主要类关系图如下:
在Spring Security 3.1的过滤器机制这篇文章中我们谈到,SS的安全管理功能是通过各种filter组成的filter过滤器链实现的,每个filter负责处理一定的功能。对于认证,在处理基于http form请求认证时,具体由org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter负责。
UsernamePasswordAuthenticationFilter继承于抽象类org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter,
AbstractAuthenticationProcessingFilter包含一重要属性,其类型是org.springframework.security.authentication.AuthenticationManager,AuthenticationManager是一个接口,定义了一个authenticate方法。
UsernamePasswordAuthenticationFilter中的attemptAuthentication方法主要逻辑如下:
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response){
UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(username, password);
this.getAuthenticationManager().authenticate(authRequest);
}
负责接收form提交的参数,构造实现org.springframework.security.core.Authentication 接口的UsernamePasswordAuthenticationToken对象,然后调用继承自AbstractAuthenticationProcessingFilter的AuthenticationManager的authenticate方法,执行认证。
AuthenticationManager是接口,SS将装配具体的实现org.springframework.security.authentication.ProviderManager来实现Authentication authenticate(Authentication authentication)方法。
ProviderManager包含了一个List<AuthenticationProvider> providers,authenticate方法的主要实现逻辑如下;
//循环providers,进行认证,通过即退出
for (AuthenticationProvider provider : getProviders()) {
result = provider.authenticate(authentication);
//如验证通过,将更详细信息copy到authentication对象中,
if (result != null) {
copyDetails(authentication, result);
break;
}
return result;
}
也就是说,ProviderManager将认证工作又具体交给org.springframework.security.authentication.AuthenticationProvider。AuthenticationProvider是接口,具体实现可由不同的实现类实现,对于认证信息存储于数据库的情况,SS将交由具体类DaoAuthenticationProvider负责。
为了灵活,DaoAuthenticationProvider将从数据库读取认证信息的工作交由org.springframework.security.core.userdetails.UserDetailsService负责,UserDetailsService是接口,org.springframework.security.core.userdetails.jdbc.JdbcDaoImpl是SS的一具体实现,当用户在配置文件中定义SQL语句时,SS缺省将调用JdbcDaoImpl进行处理。当然,用户也可自定义实现UserDetailsService接口,只要实现相应的 UserDetails loadUserByUsername(String username) 方法即可。