spring-security(十三)核心服务类

阅读更多
前言:
  在之前的篇章中我们已经讲述了spring security的部分组件,接下来我们再重点查看下另外两个重要的和认证相关的接口及其实现类:AuthenticationManager, UserDetailsService 。

1.AuthenticationManager, ProviderManager 和 AuthenticationProvider
  AuthenticationManager是认证的核心接口,里面只有一个方法authenticate,传入一个待认证的Authentication对象,再返回一个完全组装好带有权限信息的Authentication。那么在实际中他是如何执行的呢,还有如果我们想检查多个认证数据库,亦或者我们想使用两种或两种以上如数据库➕LDAP相结合的认证方式时该如何操作呢?
  在Spring Security中AuthenticationManager的默认实现者是ProviderManager,这个类本身并不进行认证操作,而是把认证过程委托给配置好的AuthenticationProvider列表,列表中的AuthenticationProvider会轮流来尝试能否完成认证。每一个具体的AuthenticationProvider在尝试认证时要么抛出异常,要么完成认证,返回一个组装好的Authentication对象(在ProviderManager中会catch认证异常继续尝试下一个provider的认证)。最常见的认证方式就是根据传入的Authentication中的用户名,调用UserDetailsService的loadUserByUsername来获取一个UserDetails对象,如有需要,此处会接着获取用户的权限信息封装成一个具体的UserDetails对象返回到具体的AuthenticationProvider类中,接着在具体的AuthenticationProvider实现类中会判断用户输入的密码和UserDetailsService返回给我们的UserDetails中的密码是否一致(如有需求,此处会先利用PasswordEncoder对用户输入的密码加密后再和UserDetails的密码比较,关于PasswordEncoder后面会再讲述),这也是DaoAuthenticationProvider这个最常用的provider的认证处理过程。获取到的UserDetails以及他包含的权限信息将被用来组装成Authentication被存储到SecurityContext中(在我们上节讨论过的AbstractSecurityInterceptor类中做的)。
  当采用spring boot的java config配置形式时,我们引入@EnableWebSecurity注解后,系统会自动为我们注册ProviderManager这个默认实现具体逻辑可参考[urlhttp://fengyilin.iteye.com/admin/blogs/2410779]spring-security(二)java config加载机制[/url],如果想追加我们自定义的provider可以使用AuthenticationManagerBuilder
@Autowired
	public void auth(AuthenticationManagerBuilder auth) throws Exception {
		auth.authenticationProvider(new MyCustomProvider());
	}

另外AuthenticationManagerBuilder也为我们提供了追加常用provider的方法
  • inMemoryAuthentication()提供基于内存的认证方式
  • jdbcAuthentication()提供基于关系数据库的认证方式
  • userDetailsService(T userDetailsService)提供基于关系数据库的认证方式,并使用我们自定义的UserDetailsService
  • ldapAuthentication()提供基于LDAP的认证方式

如果所有的provider都不支持对当前安全对象的认证,ProviderManager将抛出一个ProviderNotFoundException异常。
  在一些认证机制如基于web form提交的过滤器-UsernamePasswordAuthenticationFilter中,会注入一个ProviderManager,当需要认证时就调用ProviderManager的认证方法。有时候我们需要用的provider可以相互替换,如DaoAuthenticationProvider和LdapAuthenticationProvider会兼容所有的提供username/password的认证方式,因而他们既能用来做基于form的登录验证也可以用来做HTTP Basic认证。然而还有一些认证机制只能被特定的provider来解析,如JA-SIG CAS,通过一个service ticket来验证,所以只能使用CasAuthenticationProvider来完成认证。
2.认证成功后擦除证书信息
  默认情况下,ProviderManager会尝试擦除Authentication中的敏感凭证信息(如用户密码、service ticket)。在使用缓存user的情况下,这个会带来一点点小问题,比如在无状态的web service应用中,因为在这种应用中每次都需要进行认证。这时如果凭证信息被移除,利用缓存奖不能够重新完成认证,所以在这种场合下我们要加入自己处理,一个解决方法就是在返回给ProviderManager之前在我们的缓存实现类或者在自定义的AuthenticationProvider类中先把Authentication对象copy一份,或者将ProviderManager中的eraseCredentialsAfterAuthentication设置成false(默认true);
@Autowired
	public void auth(AuthenticationManagerBuilder auth) throws Exception {
		auth.eraseCredentials(false);
	}

3.DaoAuthenticationProvider
DaoAuthenticationProvider是最简单的AuthenticationProvider实现类,也是spring framewor最早支持的认证方式,他利用UserDetailsService的一个实现类(通过AuthenticationManagerBuilder的jdbcAuthentication()方法,我们会为DaoAuthenticationProvider提供一个实现了UserDetailsService 的JdbcUserDetailsManager)。DaoAuthenticationProvider还有一个可选的PasswordEncoder属性,用来对UserDetailsService获取到的UserDetails中的password进行编解码。后面我们会单独讨论PasswordEncoder这个类。

你可能感兴趣的:(spring,security)