Spring Security 实战 01 Security入门
Spring Security 简介
Spring Security 最早叫 Acegi Security,这个名称并不是说它和 Spring 就没有关系,它依然是为 Spring 框架提供安全支持的。和 Shiro 相比,Spring Security 重量级并且配置烦琐,自从 Spring Boot 推出后,就彻底颠覆了传统了 JavaEE 开发,自动化配置让许多事情变得非常容易,包括 Spring Security 的配置。在一个 Spring Boot 项目中,我们甚至只需要引入一个依赖,不需要任何额外配置,项目的所有接口就会被自动保护起来了。
Spring Security 核心功能
认证 (Authentication)
认证就是身份验证(你是谁?)
Spring Security 支持多种不同的认证方式,Spring Security 提供的认证机制不仅仅包括下面这些,我们还可以通过引入第三方依赖来支持更多的认证方式,同时,如果这些认证方式无法满足我们的需求,我们也可以自定义认证逻辑
- 表单认证。
- OAuth2.0 认证。
- SAML2.0 认证。
- CAS 认证。
- RememberMe 自动认证。
- JAAS 认证。
- OpenID 去中心化认证。
- Pre-Authentication Scenarios 认证。
- X509 认证。
- HTTP Basic 认证。
- HTTP Digest 认证。
AuthenticationManager
Spring Security 中的认证工作主要由 AuthenticationManager 接口来负责
AuthenticationManager 的 authenticate 提供了认证的功能
/**
返回 Authentication 代表成功
抛出 AuthenticationException 异常,代表用无凭证无效
**/
public interface AuthenticationManager {
Authentication authenticate(Authentication var1) throws AuthenticationException;
}
Authentication 的实现类
ProviderManager
ProviderManager 是 AuthenticationManager 最主要的实现类,用于管理 AuthenticationProvider , 而AuthenticationProvider 则是具体的身份认证实现
在一次完整的认证流程中,可能会同时存在多个 AuthenticationProvider(例如,项目同时支持 form 表单登录和短信验证码登录),多个 AuthenticationProvider 统一由 ProviderManager来管理。同时,ProviderManager 具有一个可选的 parent,如果所有的 AuthenticationProvider都认证失败,那么就会调用 parent 进行认证。parent 相当于一个备用认证方式,即各个
AuthenticationProvider 都无法处理认证问题的时候,就由 parent 出场收拾残局。
授权 (Authorization)
授权就是访问控制(你可以做什么?)。
Spring Security 支持基于 URL 的请求授权、支持方法访问授权、支持 SpEL 访问控制、支持域对象安全(ACL),同时也支持动态权限配置、支持 RBAC 权限模型等。
Spring Security 的授权体系中有两个关键接口
- AccessDecisionManager : 做出最终访问控制(授权)决策,在AccessDecisionManager中会挨个遍历AccessDecisionVoter,进而决定是否允许用户访问
- AccessDecisionVoter: 指示类负责对授权决策进行投票。投票的协调(即轮询AccessDecision投票者,统计他们的响应,并做出最终授权决定)由AccessDevisionManager执行。
Spring Security 中的过滤器
在 Spring Security 中,认证、授权等功能都是基于过滤器来完成的
FilterChainProxy
默认过滤器并不是直接放在 Web 项目的原生过滤器链中,而是通过一个FilterChainProxy 来统一管理。Spring Security 中的过滤器链通过 FilterChainProxy 实现 Filter 嵌入到 Web项目的原生过滤器链中。FilterChainProxy 维护了List filterChains 保存整个过滤器链
private static final Log logger = LogFactory.getLog(FilterChainProxy.class);
private static final String FILTER_APPLIED = FilterChainProxy.class.getName().concat(".APPLIED");
private List<SecurityFilterChain> filterChains;
private FilterChainValidator filterChainValidator;
private HttpFirewall firewall;
过滤器链不仅仅只有一个,可能会有多个,当存在多个过滤器链时,多个过滤器链之间要指定优先级,当请求到达后,会 从
FilterChainProxy 进行分发,先和哪个过滤器链匹配上,就用哪个过滤器链进行处理。当系统中存在多个不同的认证体系时,那么使用多个过滤器链就非常有效。
Spring Security 中常见的过滤器
保存认证数据
Spring Security 也是将登录用户数据保存到 Session 中
SecurityContextHolder
当用户登录成功后,Spring Security 会将登录成功的用户信息保存到 SecurityContextHolder中。SecurityContextHolder 中提供了一些静态方法,用于保存应用程序中当前用户的安全上下文,SecurityContextHolder 中是委托 SecurityContextHolderStrategy 来处理保存的用户数据策略。
SecurityContextHolderStrategy
Spring0 Security 中提供的三种实现
- MODE_THREADLOCAL (ThreadLocalSecurityContextHolderStrategy):将SecurityContext放在ThreadLocal中,开启子线程,子线程获取不到用户数据。
- MODE_INHERITABLETHREADLOCAL (InheritableThreadLocalSecurityContextHolderStrategy):多线程环境,子线程也能获取到用户数据。
- MODE_GLOBAL (GlobalSecurityContextHolderStrategy): SecurityContextHolderStrategy的基于静态字段的实现。
这意味着JVM中的所有实例共享相同的SecurityContext。这对于富客户端(如Swing)通常很有用。