Spring Security基础

发布时间:2021-07-29 21:59
最后更新:2021-07-29 21:59
所属分类:
JVM Spring

Spring Security 是 Spring 框架中的安全框架,整个 Spring Security 在学习起来都是比较复杂的。这也是因为 Spring Security 在设计上所需要的组件比较多,所以比较难以理解。本文将尝试通过组成 Spring Securit 功能的常用功能组件以图的形式进行说明,以方便对于 Spring Security 能有一个比较清楚直观的理解。

本篇关于 Spring Security 的文章主要由三部分组成,分别是:

  1. Spring Security基础
  2. 在Spring MVC中的配置Spring Security
  3. 在Spring WebFlux中的配置Spring Security

基础组成

SecurityContextHolder

在 Spring Security 中,SecurityContextHolder是 Spring Security 记录认证结果的核心。所有已经被认证过的用户都将被保存在SecurityContextHolder中。每个SecurityContextHolder实例中会利用一个SecurityContextHolderStrategy实例来保存已经完成验证的SecurityContext实例。

所以,在 Spring Security 中,每一个非空的SecurityContextHolder就代表着一个已经被认证过的用户,而且在 Spring Security 中,非空的SecurityContextHolder实例也常常被用来表示当前已经被认证过的用户。

以下是SecurityContextHolder系列接口的构成示意图。

从这张图上可以看出,SecurityContextHolder中主要是利用其中的SecurityContextHolderStrategy实例来管理其中持有的SecurityContext实例。但是在实际使用时,我们并不需要直接调用SecurityContextHolderStrategy实例,只需要利用SecurityContextHolder来完成操作即可。

如果想要在SecurityContextHolder中使用不同的策略实例,可以在配置文件中设定spring.security.strategy的值,这一配置项可以取以下三个值:MODE_THREADLOCALMODE_INHERITABLETHREADLOCALMODE_GLOBAL。在没有设置所需要使用的策略时,会默认采用MODE_THREADLOCAL

SpringContext

SpringContext类就比较简单了,根据上图描述,SpringContext里就是包含了一个Authentication接口实例。

Authentication

Authentication接口是Spring Security中的认证功能核心,在Spring Security中主要执行以下两个功能:

  1. 作为AuthenticationManager的输入数据来对用户进行认证。
  2. 代表一个目前已经被认证的用户,在这种情况下,Authentication实例可以从SecurityContext中获得。

Authentication中通常会包含三种内容:Principal、Credentials、Authorities。虽然在上图中,Principal和Credentials都是Object类型的,但Principal通常都是以UserDetails接口实例的形式出现,而Credentials通常都是字符串。Authorities在上图中表示是一组GrantedAuthority实例,但是大部分情况下都是采用SimpleGrantedAuthority类包装的字符串组成Authorites集合。

AuthenticationManager

AuthenticationManager在Spring Security中定义了如何执行用户身份验证,经过AuthenticationManager的执行以后,Spring Security即可以向SecurityContextHolder中写入被返回的验证信息。

AuthenticationManager通常会被应用成一个Servlet Filter,而这也是Spring MVC基于Servlet的处理流程。

由于AuthenticationManager只是一个接口,所以在实际使用时通常都使用ProviderManager类来实现其所定义的功能。常用的基于AuthenticationManager接口的类结构图如下。

AuthenticationManager类结构图
AuthenticationManager类结构图

从这张图上可以看出来,平时在使用ProviderManager的时候,实际上是在构建认证所需要的AuthenticationProvider。Spring Security提供了多个实现了AuthenticationProvider接口的抽象类,例如AbstractUserDetailsAuthenticationProvider,这些抽象类中实现了很多常用的功能,如果需要实现一个自定义AuthenticationProvider,可以直接继承这些抽象类。Spring Security中也是基于这些抽象类提供了许多常见的认证场景支持。这些常用的认证类主要有以下几个。

  1. DaoAuthenticationProvider,提供基于用户名和密码的认证。
  2. JwtAuthenticationProvider,提供基于JWT的认证。
  3. AnonymousAuthenticationProvider,提供基于AnonymousAuthenticationToken的匿名用户认证。
  4. JaasAuthenticationProvider,提供基于Java认证与授权的认证。
  5. RemoteAuthenticationProvider,提供远程认证。
  6. LdapAuthenticationProvider,提供基于LDAP的认证。
  7. OAuth2AuthenticationCodeAuthenticationProvider,提供基于授权码的OAuth 2.0认证。
  8. OAuth2LoginAuthenticationProvider,提供基于登录的OAuth 2.0认证。
  9. OpenIDAuthenticationProvider,提供基于OpenID授权的认证。
  10. PreAuthenticatedAuthenticationProvider,提供基于预认证的授权认证。
  11. CasAuthenticationProvider,提供基于JA-SIG中央认证服务的授权认证。
  12. OpaqueTokenAuthenticationProvider,提供基于不透明令牌的授权认证。
  13. JwtAuthenticationProvider,提供基于JWT的授权认证。

DaoAuthenticationProvider

DaoAuthenticationProvider是Spring Security中最常用的Authentication Provider,因为大部分认证场景都是基于用户名和密码的。DaoAuthenticationProvider进行认证功能的核心就是一个UserDetailsService实例,通过UserDetailsService可以完成用户提供的用户名和密码的验证,并且可以返回一个可供Authentication保存用户信息的UserDetails

以下是DaoAuthenticationProvider的类结构图,在构建基于用户名和密码的认证过程中参考使用。

DaoAuthenticationProvider类结构图
DaoAuthenticationProvider类结构图

AbstractAuthenticationProcessingFilter

AbstractAuthenticationProcessingFilter继承了GenericFilterBean,是Spring Servlet应用中Security相关过滤器定义的抽象类。基于Servlet的Web应用中,一个请求在到达负责响应的Controller Bean之前,需要经过数层过滤器的处理。AbstractAuthenticationProcessingFilter所执行的功能就是把Spring Security的认证与授权功能以过滤器的形式插入到Web请求的处理流程之中。

在Spring Security的官方文档中,对于过滤器的使用还提到了DelegatingFilterProxyFilterChainProxy,这两个代理类主要是用于在Servlet处理流程中插入Filter组合的,在绝大多数情况下都不需要手动控制。在使用过程中一般只需要定义所需要使用的Filter即可。

对于SecurityFilterChain在整个Servlet请求处理流程中插入的Filter的先后顺序,Spring Security官方文档是给了一个列表的,可以直接参考使用。我们在日常使用过程中所需要关注的Filter主要有以下几个(按调用顺序排列,不一定全都使用)。

  1. CorsFilter
  2. CsrfFilter
  3. LogoutFilter
  4. OAuth2AuthorizationRequestRedirectFilter
  5. OAuth2LoginAuthenticationFilter
  6. UsernamePasswordAuthenticationFilter
  7. OpenIDAuthenticationFilter
  8. BearerTokenAuthenticationFilter
  9. RememberMeAuthenticationFilter
  10. AnonymousAuthenticationFilter
  11. OAuth2AuthorizationCodeGrantFilter
  12. SessionManagementFilter
  13. ExceptionTranslationFilter

UsernamePasswordAuthenticationFilter

UsernamePasswordAuthenticationFilter为例,它会将请求传入的用户名和密码整合放入UsernamePasswordAuthenticationToken中,这是一个实现了Authentication接口的类,主要用途就是存放用户认证信息。之后,UsernamePasswordAuthenticaitonToken实例就会被放入AuthenticationManager实例中进行认证。

所以在认证过程中所获取的Authentication接口实例,一般都是UsernamePasswordAuthenticationToken类的实例。

RememberMeAuthenticationFilter

RememberMeAuthenticationFilter可以主要用来提供已经完成认证的用户自动登录功能的过滤器,通过定义一个RememberMeServices接口或者AbstractRememberMeServices抽象类的实例,可以利用其中的loginSuccess()方法生成一个针对于已经完成认证的用户的记录,这种记录可以是Token、Cookie或者其他任何形式。所生成的用户记录可以在下一次请求的autoLogin()方法中使用,并在请求中恢复认证记录。

BearerTokenAuthenticationFilter

BearerTokenAuthenticaitonFilter的主要功能就是解析HTTP请求头中的Authorization,并将其中所携带的Token内容解析出来,形成一个BearerTokenAuthenticationToken实例,然后放入AuthenticationManager中进行认证,最后将认证结果放入SecurityContextHolder中。这里出现的BearerTokenAuthenticationToken也是一个AbstractAuthenticationToken抽象类的子类,其中也包含了认证所需要使用的用户名、认证资料等。

Spring MVC中的认证流程

Spring MVC中主要是依赖于Servlet Filter组成的管道来对HTTP请求中携带的认证消息进行处理。下面借用一个伪数据流图来简单示意一下在一次Web请求中认证信息的处理过程。

Spring MVC认证流程示意
Spring MVC认证流程示意

从这个图上可以看出来,在Spring MVC中,这些实现了javax.servlet.Filter的认证过滤器才是才是真正启动认证过程执行的起点。而我们在使用时大多只需要为它们提供它们所依赖的工作实例即可,例如UserDetailsServicePasswordEncoder等。

Spring WebFlux中的认证流程

Spring WebFlux中的依赖的是WebFilter组成的过滤器管道来对HTTP请求中携带的认证消息进行处理。这里同样借用一个伪数据流图来进行简单的示意。

Spring WebFlux认证流程示意
Spring WebFlux认证流程示意

Spring WebFlux中的认证流程和参与组件要比Spring MVC少很多。从上图可以看出来,启动认证过程的起点依旧是实现了WebFilter接口的过滤器,但是不同的认证过滤器开始使用不同的AuthenticationManager实例。但是整个流程中不变的是,所有已经完成认证的结果还都将保存到SecurityContext实例中。


索引标签
Java
Spring
Spring Security
安全认证