SpringSecurity学习笔记——SpringSecurity底层原理

五、SpringSecurity底层原理


1、SpringSecurity过滤介绍

SpringSecurity 采用的是责任链的设计模式,它有一条很长的过滤器链。

现在对这条过滤器链的 15 个过滤器进行说明:

  1. WebAsyncManagerIntegrationFilter:将 Security 上下文与 Spring Web 中用于处理异步请求映射的 WebAsyncManager 进行集成。
  2. SecurityContextPersistenceFilter:在每次请求处理之前将该请求相关的安全上下文信息加载到 SecurityContextHolder 中,然后在该次请求处理完成之后,将SecurityContextHolder 中关于这次请求的信息存储到一个“仓储”中,然后将SecurityContextHolder 中的信息清除,例如在 Session 中维护一个用户的安全信息就是这个过滤器处理的。
  3. HeaderWriterFilter:用于将头信息加入响应中。
  4. CsrfFilter:用于处理跨站请求伪造。
  5. LogoutFilter:用于处理退出登录。
  6. UsernamePasswordAuthenticationFilter:用于处理基于表单的登录请求,从表单中获取用户名和密码。默认情况下处理来自 /login 的请求。从表单中获取用户名和密码时,默认使用的表单 name 值为 username 和 password,这两个值可以通过设置这个过滤器的 usernameParameter 和 passwordParameter 两个参数的值进行修改。
  7. DefaultLoginPageGeneratingFilter:如果没有配置登录页面,那系统初始化时就会配置这个过滤器,并且用于在需要进行登录时生成一个登录表单页面。
  8. BasicAuthenticationFilter:检测和处理 http basic 认证。
  9. RequestCacheAwareFilter:用来处理请求的缓存。
  10. SecurityContextHolderAwareRequestFilter:主要是包装请求对象 request。
  11. AnonymousAuthenticationFilter:检测 SecurityContextHolder 中是否存在Authentication 对象,如果不存在为其提供一个匿名 Authentication。
  12. SessionManagementFilter:管理 session 的过滤器
  13. ExceptionTranslationFilter:处理 AccessDeniedException 和AuthenticationException 异常。
  14. FilterSecurityInterceptor:可以看做过滤器链的出口。
  15. RememberMeAuthenticationFilter:当用户没有登录而直接访问资源时, 从 cookie 里找出用户的信息, 如果 Spring Security 能够识别出用户提供的 remember me cookie, 用户将不必填写用户名和密码, 而是直接登录进入系统,该过滤器默认不开启。

2、SpringSecurity 基本流程

  1. Spring Security 采取过滤链实现认证与授权,只有当前过滤器通过,才能进入下一个过滤器
    • 重点介绍以下三个过滤器:
      • UsernamePasswordAuthenticationFilter 过滤器:该过滤器会拦截前端提交的 POST 方式的登录表单请求,并进行身份认证
      • ExceptionTranslationFilter 过滤器:该过滤器不需要我们配置,对于前端提交的请求会直接放行,捕获后续抛出的异常并进行处理(例如:权限访问限制)。
      • FilterSecurityInterceptor 过滤器:该过滤器是过滤器链的最后一个过滤器,根据资源权限配置来判断当前请求是否有权限访问对应的资源。如果访问受限会抛出相关异常,并由 ExceptionTranslationFilter 过滤器进行捕获和处理。

3、 SpringSecurity 认证流程(重点)

认证过程图:

  1. UsernamePasswordAuthenticationFilter 源码

    • 当前端提交的是一个 POST 方式的登录表单请求,就会被该过滤器拦截,并进行身份认证。该过滤器的 doFilter() 方法实现在其抽象父类AbstractAuthenticationProcessingFilter中,查看相关源码:

      • image-20210824143821136
      • image-20210824144331667
      • image-20210824144556588
      • image-20210824144718624
      • image-20210824144956513
    • 上述的 第二 过程调用了 UsernamePasswordAuthenticationFilter 的 attemptAuthentication() 方法,源码如下:

      • image-20210824145831124
      • image-20210824171033872
    • 上述的(3)过程创建的 UsernamePasswordAuthenticationToken是 Authentication 接口的实现类,该类有两个构造器,一个用于封装前端请求传入的未认证的用户信息,一个用于封装认证成功后的用户信息:

      • image-20210824171514677
      • image-20210824172407929
    • Authentication 接口的实现类用于存储用户认证信息,查看该接口具体定义:

      • image-20210824172835092
  2. ProviderManager 源码

    • 上述过程中,UsernamePasswordAuthenticationFilter 过滤器的 attemptAuthentication() 方法的**(5)过程**将未认证的 Authentication 对象传入ProviderManager 类的 authenticate() 方法进行身份认证。

    • ProviderManager 是 AuthenticationManager 接口的实现类,该接口是认证相关的核心接口,也是认证的入口。在实际开发中,我们可能有多种不同的认证方式,例如:用户名+密码、邮箱+密码、手机号+验证码等,而这些认证方式的入口始终只有一个,那就是AuthenticationManager。在该接口的常用实现类 ProviderManager 内部会维护一个**List<AuthenticationProvider>**列表,存放多种认证方式,实际上这是委托者模式(Delegate)的应用。每种认证方式对应着一个 AuthenticationProvider,AuthenticationManager 根据认证方式的不同(根据传入的 Authentication 类型判断)委托对应的 AuthenticationProvider 进行用户认证。

      • image-20210824174402462
      • image-20210825091550348
      • image-20210825092028834
      • image-20210825092158156
    • 上述认证成功之后的(6)过程,调用 CredentialsContainer 接口定义的eraseCredentials() 方法去除敏感信息。查看UsernamePasswordAuthenticationToken 实现的 eraseCredentials() 方法,该方法实现在其父类中:

      • image-20210825092841825
  3. 认证成功/失败处理

    • 上述过程就是认证流程的最核心部分,接下来重新回到UsernamePasswordAuthenticationFilter 过滤器的 doFilter() 方法,查看认证成功/失败的处理:
      • image-20210825093609101
    • 查看successfulAuthentication()和unsuccessfulAuthentication()方法源码︰
      • image-20210825094307885
  4. 总体方法结构:

4、SpringSecurity登录认证流程

  • UsernamePasswordAuthenticationFilter 父类 AbstractAuthenticationProcessingFilter 的 doFilter 方法
  • UsernamePasswordAuthenticationFilter 的 attemptAuthentication 方法对前端传过来的用户名和密码进行封装
  • ProviderManager 的 authenticate 方法开始认证
  • DaoAuthenticationProvider 父类 AbstractUserDetailsAuthenticationProvider 的 authenticate 方法
  • DaoAuthenticationProvider 的 retrieveUser 方法
  • UserDetailsService接口 的 loadUserByUsername方法(一般都由我们自己实现)从数据库获得用户具体数据
  • AbstractAuthenticationProcessingFilter 的 successfulAuthentication(我们可以重写返回自定义成功)

5、SpringSecurity 权限访问流程

主要是对ExceptionTranslationFilter 过滤器和 FilterSecurityInterceptor 过滤器进行介绍。

  1. ExceptionTranslationFilter 过滤器
    • 该过滤器是用于处理异常的,不需要我们配置,对于前端提交的请求会直接放行,捕获后续抛出的异常并进行处理(例如:权限访问限制)。具体源码如下:image-20210825094732062
  2. FilterSecurityInterceptor 过滤器
    • FilterSecurityInterceptor 是过滤器链的最后一个过滤器,该过滤器是过滤器链的最后一个过滤器,根据资源权限配置来判断当前请求是否有权限访问对应的资源。如果访问受限会抛出相关异常,最终所抛出的异常会由前一个过滤器ExceptionTranslationFilter 进行捕获和处理。具体源码如下:
      • image-20210825094939801
      • image-20210825095108336

6、 SpringSecurity 请求间共享认证信息

  • 一般认证成功后的用户信息是通过 Session 在多个请求之间共享,那么 Spring Security 中是如何实现将已认证的用户信息对象 Authentication 与 Session 绑定的进行具体分析。
    • 共享认证信息流程图:
    • 在前面讲解认证成功的处理方法 successfulAuthentication() 时,有以下代码:
      • image-20210825095414768
    • 查 看 SecurityContext 接 口 及 其 实 现 类 SecurityContextImpl , 该 类 其 实 就 是 对Authentication 的封装
    • 查 看 SecurityContextHolder 类 , 该 类 其 实 是 对 ThreadLocal 的 封 装 , 存 储SecurityContext 对象
      • image-20210825095821705
      • image-20210825100128004
      • image-20210825100327759
      • image-20210825100449178
  • SecurityContextPersistenceFilter 过滤器
    • UsernamePasswordAuthenticationFilter 过滤器认证成功之后,会在认证成功的处理方法中将已认证的用户信息对象 Authentication 封装进SecurityContext,并存入 SecurityContextHolder。
    • 之后,响应会通过 SecurityContextPersistenceFilter 过滤器,该过滤器的位置在所有过滤器的最前面,请求到来先进它,响应返回最后一个通过它,所以在该过滤器中处理已认证的用户信息对象 Authentication 与 Session 绑定。
    • 认证成功的响应通过 SecurityContextPersistenceFilter 过滤器时,会从SecurityContextHolder 中取出封装了已认证用户信息对象 Authentication 的SecurityContext,放进 Session 中。当请求再次到来时,请求首先经过该过滤器,该过滤器会判断当前请求的 Session 是否存有 SecurityContext 对象,如果有则将该对象取出再次放入 SecurityContextHolder 中,之后该请求所在的线程获得认证用户信息,后续的资源访问不需要进行身份认证;当响应再次返回时,该过滤器同样从 SecurityContextHolder 取出SecurityContext 对象,放入 Session 中。具体源码如下:
      • image-20210825100929352
      • image-20210825101133653
  • 1
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值