背景
- 一个系统总会遇到安全,权限的问题,并且一坨坨的术语,让人恼火;更恼火的是官方一坨坨的代码实现,理不清剪不断;最最恼火的是你还得重新注入自己的一些实现,比如个性话的用户、个性化的权限,不得不重写一些接口和实现。
- 最好的办法是,大概理清它们在哪里,然后,不至于想实现的时候找不到路径,那么一起看看spring security的基本原理和实现,以及若依又如何使用的,才会到以后该如何自己整一套。
Spring Security简介
- Spring Security 最早叫 Acegi Security, 这个名称并不是说它和 Spring 就没有关系,它依然是为Spring 框架提供安全支持的。Acegi Security 基于 Spring,可以帮助我们为项目建立丰富的角色与权限管理系统。Acegi security 虽然好用,但是最为人诟病的则是它臃肿烦琐的配置这一问题最终也遗传给了 Spring Security。
- Acegi Security 最终被并入 Spring Security 项目中,并于 2008 年4月发布了改名后的第一个版本 Spring Security 2.0.0,到目前为止,Spring Security 的最新版本己经到了 5.6.1。和 Shiro 相比,Spring Security重量级并且配置烦琐,直至今天,依然有人以此为理由而拒绝了解 Spring Security。其实,自从 Spring Boot 推出后,就彻底颠覆了传统了 JavaEE 开发,自动化配置让许多事情变得非常容易,包括 Spring Security 的配置。在一个 Spring Boot 项目中,我们甚至只需要引入一个依赖,不需要任何额外配置,项目的所有接口就会被自动保护起来了。在 Spring Cloud中,很多涉及安全管理的问题,也是一个 Spring Security 依赖两行配置就能搞定,在和 Spring 家族的产品一起使用时,Spring Security 的优势就非常明显了。
整体架构
- 通过上一节,对于基本术语我们比较熟悉了,核心就是认证和授权,您是谁,您有什么权利,这两个看着有点相似的词一定区分好,Authentication (认证),Authorization(授权),AuthenticationManager 主要实现类为 ProviderManager,在 ProviderManager 中管理了众多 AuthenticationProvider 实例。很明显,可以有多个provider,允许有多种认证方式。SecurityContextHolder 用来获取登录之后用户信息。
- AccesDecisionVoter 和 AccessDecisionManager 都有众多的实现类,在 AccessDecisionManager 中会换个遍历 AccessDecisionVoter,进而决定是否允许用户访问,因而 AaccesDecisionVoter 和 AccessDecisionManager 两者的关系类似于 AuthenticationProvider 和 ProviderManager 的关系。
基本原理
- 在 Spring Security 中 认证、授权 等功能都是基于过滤器完成的。需要注意的是,默认过滤器并不是直接放在 Web 项目的原生过滤器链中,而是通过一个 FlterChainProxy 来统一管理。Spring Security 中的过滤器链通过 FilterChainProxy 嵌入到 Web项目的原生过滤器链中。FilterChainProxy 作为一个顶层的管理者,将统一管理 Security Filter。FilterChainProxy 本身是通过 Spring 框架提供的 DelegatingFilterProxy 整合到原生的过滤器链中。
Security Filters
- 可以看出,Spring Security 提供了 30 多个过滤器。默认情况下Spring Boot 在对 Spring Security 进入自动化配置时,会创建一个名为 SpringSecurityFilerChain 的过滤器,并注入到 Spring 容器中,这个过滤器将负责所有的安全管理,包括用户认证、授权、重定向到登录页面等。SpringBootWebSecurityConfiguration这个类是 spring boot 自动配置类,通过这个源码得知,默认情况下对所有请求进行权限控制:
- 中间省略一坨坨的逻辑分析,spring security 会到usreDetailService, 也就是及时没有持久化,也能看到登录
- 绕了很多,我们回到如何自定义的认证以及自定义的授权,划重点,WebSecurityConfigurerAdapter 扩展 Spring Security 所有默认配置
- 会用这个就可以,不能再看多了,越看越乱,不如我们看若依是如何实践这个内容的。
若依的安全
安全的配置
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter
- 里面的细节都要挨着读一读的,看代码最有意思
若依登陆过程及过滤器拦截器的使用:
用户登陆接口:1、把用户信息通过uuid即token作为key,存储在缓存中,并设置过期时间,2、通过jwt存储token,userId,userName在map中,设置过期时间,通过jwt创建一个编码后的access_token和expireTime,并返回token在前端
过滤器:用户前端传递的access_token通过Jwt解析,尝试获取userkey(即token),userid,username
并判断是否过期,为空等。如果异常即刻报错,否则将解析的userkey,userid,username纳入请求头中,请求接着交给拦截器。
拦截器:拦截器从请求头中获取userkey,userid,username,通过userkey从缓存中获取用户信息,并刷新缓存中用户信息的过期时间。并将用户信息加入到本地的TransmittableThreadLocal<Map<String, Object>>中,方便用户获取当前用户信息。
当然还有的很多内容,比如记住我,验证码, CSRF 漏洞保护,跨域,异常处理等等,都需要在这个基础上展开。
总结
在 Spring Security 中 认证、授权 等功能都是基于过滤器完成的。
如何自定义自己的一些安全策略, WebSecurityConfigurerAdapter 扩展 Spring Security 所有默认配置