日常bb

日常bb

Spring Security

70
2022-10-02
Spring Security

Spring Security

Spring Security是一个功能强大且高度可定制的身份验证和访问控制框架。

它是保护基于Spring的应用程序的官方标准。毕竟是全家桶套餐中的一员。Spring Security是一个专注于为Java应用程序提供身份验证和授权的框架。 像所有Spring项目一样,Spring Security的真正强大之处在于它可以轻松扩展以满足自定义需求。

核心功能

  1. 认证(你是谁)
  2. 授权(你能干啥)
  3. 攻击防护(防止伪造身份)

基本原理

Spring Security基本原理图

上面是Spring Security的基本原理图,最右边就是我们的Controller接口,前面的所有都是过滤器。

简单理解:Spring Security就是一组过滤器,它的核心也就是这样的一条过滤链,访问的所有请求都会经过 Spring Security 的过滤器。

过滤器链上有很多的过滤器,它们的作用就是用来校验用户的身份,每一个过滤器负责处理一种认证方式。

比如:http.formLogin()对应着UsernamePasswordAuthenticationFilter过滤器。
比如:http.httpBasic()对应着BasicAuthenticationFilter过滤器。

请求到达过滤器时,如UsernamePasswordAuthenticationFilter这个过滤器时,就会触发当前请求是否是一个登陆请求,判断请求中是否携带用户名和密码等。如果符合条件,那么过滤器就会试图去登陆,若是不满足条件,就会下发给下一个过滤器。

例如UsernamePasswordAuthenticationFilter下一个过滤器是BasicAuthenticationFilter。到达BasicAuthenticationFilter后又会判断是否触发当前过滤器的条件,如请求头中是否携带Basic 登陆的信息,如果有就会尝试解码和登陆。

其他自定义过滤器也是同样的逻辑,按照这个流程一个个的往下走。

如果在某个过滤器上认证成功后会在请求上做一个标记,用来表示当前这个请求的用户授权成功了。

ExceptionTranslationFilter

ExceptionTranslationFilter异常转换过滤器位于整个过滤链的后方,用来转换整个链路中出现的异常,将其转化,顾名思义,转化以意味本身并不处理。

一般其只处理两大类异常:

  • AccessDeniedException访问异常;
  • AuthenticationException认证异常;

这个过滤器非常重要,因为它将Java中的异常和HTTP 的响应连接在了一起,这样在处理异常时,我们不用考虑密码错误该跳到什么页面,账号锁定该如何,只需要关注自己的业务逻辑,抛出相应的异常便可。

如果该过滤器检测到AuthenticationException,则将会交给内部的AuthenticationEntryPoint去处理,如果检测到AccessDeniedException,需要先判断当前用户是不是匿名用户,如果是匿名访问,则和前面一样运行AuthenticationEntryPoint,否则会委托给AccessDeniedHandler去处理,而AccessDeniedHandler的默认实现,是AccessDeniedHandlerImpl

所以ExceptionTranslationFilter内部的AuthenticationEntryPoint是至关重要的,顾名思义:认证的入口点。

已注销-ExceptionTranslationFilter详解

FilterSecurityInterceptor

走过前面所有的过滤器后最后会来到FilterSecurityInterceptor,这个过滤器是整个 Spring Security 过滤器链上的最后一环,它能够决定请求能不能访问 API 请求。

FilterSecurityInterceptorSecurityContextHolder中获取Authentication对象,然后比对用户拥有的权限和资源所需的权限。前者可以通过Authentication对象直接获得,而后者则需要引入我们之前一直未提到过的两个类:SecurityMetadataSourceAccessDecisionManager

已注销-FilterSecurityInterceptor详解
银河架构师-FilterSecurityInterceptor详解

表单认证

程序员劝退师-TAO-SpringSecurity表单认证

源码分析

Spring Security认证流程

AuthenticationManager自己并不包含验证的逻辑,它的作用是用来管理AuthenticationProvider

getProviders()会拿到整个系统中所有实现AuthenticationProvider的实现类,这里上面提到的AuthenticationManager就是来收集并管理所有AuthenticationProvider的实现类,这里就会循环挨个去比对上面AuthenticationToken类型。

不同的Provider支持的Authentication类型是不一样的,根据传入的Authentication类型这里会挑出一个进行校验处理。

程序员劝退师-TAO-SpringSecurity表单登录流程源码分析

认证的结果如何在请求间共享

认证结果共享

程序员劝退师-TAO-SpringSecurity认证的结果在请求间共享

授权流程

Spring Security真正判断请求能否通过是在FilterSecurityInterceptor过滤器中处理的,如果请求不能通过的话就会根据不同的原因抛出异常,抛出异常以后就会由ExceptionTranslationFilter这个过滤器接收处理。

但有一个特殊的过滤器AnonymousAuthenticationFilter

AnonymousAuthenticationFilter

AnonymousAuthenticationFilter中的逻辑比较简单,就是判断当前的SecurityContextHolder中是否有authentication,是否等于null

这里的判断实际上就在在判断前面的过滤器是否完成身份的认证,或者在Session中拿到身份的证信息。

如果前面的过滤器一个都没认证的话,那么就会创建一个authentication然后setSecurityContextHolder中,这里放的并不是认证成功后的用户信息,而是一个字符串anonymousUser

Spring Security中,AnonymousAuthenticationFilter是所有认证过滤器的最后一个,也就是不管你前面有没有身份认证成功,SecurityContextHolder中一定是会放一个authentication的。如果前面的过滤器认证成功了,那么放的就是用户身份信息,如果一个都没成功,那么就是一个字符串anonymousUser

授权流程

核心:FilterSecurityInterceptorAccessDecisionManagerAccessDecisionVoter

FilterSecurityInterceptor:它是授权的主入口。

AccessDecisionManager:访问决定的管理者,是一个接口,它有一个抽象实现AbstractAccessDecisionManager和三个具体实现AffirmativeBasedConsensusBasedUnanimousBase。它也管理者一组AccessDecisionVoter

AccessDecisionVoter:从名字就能看出它是做投票的。

AccessDecisionManager收到一个请求时这一组AccessDecisionVoter会根据自己的逻辑判断这个请求时过还是不过。
判断有三套逻辑:

  • AffirmativeBased:不管有多少个AccessDecisionVoter投不过,只要有一个投通过,那么请求就可以访问。(Spring Security的默认实现逻辑)
  • UnanimousBased:不管有多少个AccessDecisionVoter投通过,只要有一个投不通过,那么请求就不可以访问。
  • ConsensusBased:判断通过的AccessDecisionVoter多还是不通过的多,哪个多就是哪个。

在判断一个请求能不能过需要两块数据:ConfigAttributeAuthentication

ConfigAttribute

请求的权限信息ConfigAttribute。例:a请求需要什么权限,b请求需要什么权限。

请求到达FilterSecurityInterceptor时就会把这个请求路径所需的权限读出来,封装成一组ConfigAttribute对象。

Authentication

Authentication实际上就是当前请求的用户的权限信息,也就是当前用户有哪些权限,这个信息就是封装在Authentication里。