spring-security–基础–01–概念和理论
1、介绍
- 是一款控制基于SpringAOP或者Servlet过滤器的安全框架。
- 责任链的设计模式
1.1、参考手册
https://www.springcloud.cc/spring-security-zhcn.html
2、核心功能
- 认证(你是谁)
- 授权(你能干什么)
- 攻击防护(防止伪造身份)
- 一组过滤器链,项目启动后将会自动配置。
3、结构总览
- SpringSecurity 要解决安全访问控制问题,而安全访问控制功能其实就是对所有进入系统的请求进行拦截,校验每个请求是否能够访问它所期望的资源。
- SpringSecurity对Web资源的保护是靠Filter实现的。
- 当初始化SpringSecurity时,会创建一个名为SpringSecurityFilterChain的Servlet过滤器,类型为org.springframework.security.web.FilterChainProxy,它实现了javax.servlet.Filter,因此外部的请求会经过此类,下图是SpringSecurity过虑器链结构图:
4、FilterChainProxy
- 是一个代理。
- 真正起作用的是FilterChainProxy中SecurityFilterChain所包含的各个Filter,同时这些Filter作为Bean被Spring管理,它们是SpringSecurity核心,他们并不直接处理用户的认证,也不直接处理用户的授权,而是把它们交给了认证管理器(AuthenticationManager)和决策管理器(AccessDecisionManager)进行处理
下图是FilterChainProxy相关类的UML图示。
5、主要的几个过滤器
5.1、SecurityContextPersistenceFilter
- 这个Filter是整个拦截过程的入口和出口(也就是第一个和最后一个拦截器)
- 请求开始时
- 从配置好的SecurityContextRepository中获取SecurityContext,然后把它设置给SecurityContextHolder。
- 请求完成后
- 将SecurityContextHolder持有的SecurityContext保存到配置好的SecurityContextRepository。同时清除securityContextHolder所持有的SecurityContext。
5.2、UsernamePasswordAuthenticationFilter
- 用于处理来自表单提交的认证。
- 表单必须提供对应的用户名和密码,其内部还有登录成功或失败后进行处理的AuthenticationSuccessHandler和AuthenticationFailureHandler。
5.3、FilterSecurityInterceptor
- 是用于保护web资源的
- 使用AccessDecisionManager对当前用户进行授权访问
5.4、ExceptionTranslationFilter
- 能够捕获来自FilterChain所有的异常,并进行处理。
- 它只会处理两类异常:AuthenticationException和AccessDeniedException,其它的异常它会继续抛出。
6、认证流程
- 用户提交用户名、密码被SecurityFilterChain中的UsernamePasswordAuthenticationFilter过滤器获取到,封装为请求Authentication,通常情况下是UsernamePasswordAuthenticationToken这个实现类。
- 然后过滤器将Authentication提交至认证管理器(AuthenticationManager)进行认证
- 认证成功后,AuthenticationManager身份管理器返回一个被填充满了信息的(包括上面提到的权限信息,身份信息,细节信息,但密码通常会被移除)Authentication实例。
- SecurityContextHolder安全上下文容器将第3步填充了信息的Authentication,通过SecurityContextHolder.getContext().setAuthentication(…)方法,设置到其中。
6.1、总结
- AuthenticationManager接口(认证管理器)是认证相关的核心接口,也是发起认证的出发点,它的实现类为ProviderManager。
- SpringSecurity支持多种认证方式,因此ProviderManager维护着一个List列表,存放多种认证方式,最终实际的认证工作是由AuthenticationProvider完成的。
- 、web表单的对应的AuthenticationProvider实现类为DaoAuthenticationProvider,它的内部又维护着一个UserDetailsService负责UserDetails的获取。最终AuthenticationProvider将UserDetails填充至Authentication。
7、认证核心组件的大体关系如下:
8、SpringSecurity的授权流程如下:
- SpringSecurity可以通过http.authorizeRequests()对web请求进行授权保护。
- SpringSecurity使用标准Filter建立了对web请求的拦截,最终实现对资源的授权访问
8.1、授权流程
- 拦截请求,已认证用户访问受保护的web资源将被SecurityFilterChain中的FilterSecurityInterceptor的子类拦截。
- 获取资源访问策略
- FilterSecurityInterceptor会从SecurityMetadataSource的子类DefaultFilterInvocationSecurityMetadataSource获取要访问当前资源所需要的权限Collection。
- SecurityMetadataSource其实就是读取访问策略的抽象,而读取的内容,其实就是我们配置的访问规则,读取访问策略如:
- 最后,FilterSecurityInterceptor会调用AccessDecisionManager进行授权决策,若决策通过,则允许访问资源,否则将禁止访问。
8.2、AccessDecisionManager授权决策
decide方法就是用来鉴定当前用户是否有访问对应受保护资源的权限
8.3、AccessDecisionManager采用投票的方式来确定是否能够访问受保护资源
AccessDecisionManager中包含的一系列AccessDecisionVoter将会被用来对Authentication是否有权访问受保护对象进行投票,AccessDecisionManager根据投票结果,做出最终决策。
8.4、AccessDecisionManager实现类
-
AffirmativeBased:默认
- 只要有AccessDecisionVoter的投票为ACCESS_GRANTED则同意用户进行访问
- 如果全部弃权也表示通过
- 如果没有一个人投赞成票,但是有人投反对票,则将抛出AccessDeniedException
-
ConsensusBased
-
如果赞成票多于反对票则表示通过。
-
如果反对票多于赞成票则将抛出AccessDeniedException
-
如果赞成票与反对票相同且不等于0,并且属性allowIfEqualGrantedDeniedDecisions的值为true,则表示通过,否则将抛出异常AccessDeniedException。
- 参数allowIfEqualGrantedDeniedDecisions的值默认为true。
-
如果所有的AccessDecisionVoter都弃权了,则将视参数allowIfAllAbstainDecisions的值而定,如果该值为true则表示通过,否则将抛出异常AccessDeniedException。
- 参数allowIfAllAbstainDecisions的值默认为false。
-
-
UnanimousBased
- 与上面两种实现有点不一样,上面两种会一次性把受保护对象的配置属性全部传递给AccessDecisionVoter进行投票,而UnanimousBased会一次只传递一个ConfigAttribute给AccessDecisionVoter进行投票。
- UnanimousBased的逻辑具体
- 如果受保护对象配置的某一个ConfigAttribute被任意的AccessDecisionVoter反对了,则将抛出AccessDeniedException。
- 如果没有反对票,但是有赞成票,则表示通过。(
- 如果全部弃权了,则将视参数allowIfAllAbstainDecisions的值而定
- true则通过
- false则抛出AccessDeniedException。
9、授权
9.1、调用accessDecisionManager进行授权决策
9.2、方式
- web授权
- 通过url拦截进行授权
- 拦截器为FilterSecurityInterceptor
- 方法授权
- 通过方法拦截进行授权
- 拦截器为MethodSecurityInterceptor
- 同时通过web授权和方法授权
- 先执行web授权,再执行方法授权,最后决策通过则允许访问资源,否则将禁止访问