Spring Security是什么
Spring Security是一个能够为基于Spring的企业应用系统提供声明式的安全访问控制解决方案的安全框架。它提供了一组可以在Spring应用上下文中配置的Bean(注:包括认证与权限获取、配置、处理相关实例),充分利用了Spring IoC,DI(控制反转Inversion of Control ,DI:Dependency Injection 依赖注入)和AOP(面向切面编程)(注:代理增强类)功能,为应用系统提供声明式的安全访问控制功能,减少了为企业系统安全控制编写大量重复代码的工作。
核心类库与认证流程
核心验证器
AuthenticationManager
该对象提供了认证方法的入口,接收一个Authentiaton
对象作为参数;
public interface AuthenticationManager {Authentication authenticate(Authentication authentication) throws AuthenticationException; }
验证逻辑
AuthenticationManager
接收 Authentication
对象作为参数,并通过 authenticate(Authentication)
方法对其进行验证;AuthenticationProvider
实现类用来支撑对 Authentication
对象的验证动作;UsernamePasswordAuthenticationToken
实现了 Authentication
主要是将用户输入的用户名和密码进行封装,并供给 AuthenticationManager
进行验证;验证完成以后将返回一个认证成功的 Authentication
对象;
ProviderManager
它是 AuthenticationManager
的一个实现类,提供了基本的认证逻辑和方法;它包含了一个 List<AuthenticationProvider>
对象,通过 AuthenticationProvider 接口来扩展出不同的认证提供者(当Spring Security
默认提供的实现类不能满足需求的时候可以扩展AuthenticationProvider
覆盖supports(Class<?> authentication)
方法);
实现逻辑
public Authentication authenticate(Authentication authentication) throws AuthenticationException { //#1.获取当前的Authentication的认证类型 Class<? extends Authentication> toTest = authentication.getClass(); AuthenticationException lastException = null; Authentication result = null; boolean debug = logger.isDebugEnabled(); //#2.遍历所有的providers使用supports方法判断该provider是否支持当前的认证类型,不支持的话继续遍历 for (AuthenticationProvider provider : getProviders()) { if (!provider.supports(toTest)) { continue; } if (debug) { logger.debug("Authentication attempt using " + provider.getClass().getName()); } try { #3.支持的话调用provider的authenticat方法认证 result = provider.authenticate(authentication); if (result != null) { #4.认证通过的话重新生成Authentication对应的Token copyDetails(authentication, result); break; } } catch (AccountStatusException e) { prepareException(e, authentication); // SEC-546: Avoid polling additional providers if auth failure is due to // invalid account status throw e; } catch (InternalAuthenticationServiceException e) { prepareException(e, authentication); throw e; } catch (AuthenticationException e) { lastException = e; } } if (result == null && parent != null) { // Allow the parent to try. try { #5.如果#1 没有验证通过,则使用父类型AuthenticationManager进行验证 result = parent.authenticate(authentication); } catch (ProviderNotFoundException e) { // ignore as we will throw below if no other exception occurred prior to // calling parent and the parent // may throw ProviderNotFound even though a provider in the child already // handled the request } catch (AuthenticationException e) { lastException = e; } } #6. 是否擦除敏感信息 if (result != null) { if (eraseCredentialsAfterAuthentication && (result instanceof CredentialsContainer)) { // Authentication is complete. Remove credentials and other secret data