SpringBoot整合SpringSecurity+JWT+Redis实现前后端分离认证授权 - 认证流程

SpringSecurity认证流程详解

1.登录校验流程

SpringBoot整合SpringSecurity+JWT+Redis实现前后端分离认证授权 - 认证流程_第1张图片

2. SpringSecurity原理解析

在继续深入向下的学习前,有必要理解清楚 Spring Security 的认证流程,这样才能理解为什么要这样写代码,也方便后续的扩展。

2.1 认证流程

2.1.1 原理初探

SpringSecurity的本质是一个过滤器链,以上列举了几个核心的过滤器,我们通过debugger的方式查看一下SpringSecurity完整的过滤器:
SpringBoot整合SpringSecurity+JWT+Redis实现前后端分离认证授权 - 认证流程_第2张图片
这就是SpringSecurity完整的过滤器链,总共有16个,不需要每个都去了解,在这里我们只讲几个重点的过滤器。

2.1.2 核心过滤器及认证流程

SpringBoot整合SpringSecurity+JWT+Redis实现前后端分离认证授权 - 认证流程_第3张图片

上图是 Spring Security 认证流程的一部分,下面的讲解以上图为依据。

1. 用户发起表单登录请求后,首先进入 UsernamePasswordAuthenticationFilter

SpringBoot整合SpringSecurity+JWT+Redis实现前后端分离认证授权 - 认证流程_第4张图片

说明: 我们看以上源代码可知,在这个UsernamePasswordAuthenticationFilter 针对post方式的/login请求进行拦截,在这里面主要就是做了一件事,就是将前端传来的用户名,密码构建出一个UsernamePasswordAuthenticationToken 对象,这个对象是Authentication的一个子类,Authentication就是认证对象

在UsernamePasswordAuthenticationFilter值得关注的就是构建UsernamePasswordAuthenticationFilter的时候是这样的:

SpringBoot整合SpringSecurity+JWT+Redis实现前后端分离认证授权 - 认证流程_第5张图片

2. 接下来将这个没有认证的对象UsernamePasswordAuthenticationToken 交给AuthenticationManager 来处理:

AuthenticationManager 内部不做任何的认证逻辑处理,其核心和管理所有的AuthenticationProvider

3.接下来由AuthenticationManager 的实现类ProviderManager来挑选由谁来处理认证逻辑:
SpringBoot整合SpringSecurity+JWT+Redis实现前后端分离认证授权 - 认证流程_第6张图片

说明: Spring Security 支持多种认证逻辑,每一种认证逻辑的认证方式其实就是一种 AuthenticationProvider。通过 getProviders() 方法就能获取所有的 AuthenticationProvider,通过 provider.supports() 来判断 provider 是否支持当前的认证逻辑。当选择好一个合适的 AuthenticationProvider 后,通过 provider.authenticate(authentication) 来让 AuthenticationProvider 进行认证

用户名密码的认证方式是由AbstractUserDetailsAuthenticationProvider 进行处理的:
SpringBoot整合SpringSecurity+JWT+Redis实现前后端分离认证授权 - 认证流程_第7张图片
AbstractUserDetailsAuthenticationProvider内部通过retrieveUser来获取 UserDetails对象,retrieveUser() 的具体实现在 DaoAuthenticationProvider 中:
SpringBoot整合SpringSecurity+JWT+Redis实现前后端分离认证授权 - 认证流程_第8张图片

loadUserByUsername是由UserDetailsService接口提供的方法,默认实现是SpringSecrity在内存中读取的,后期我们做自己的项目可以写个实现类去重写loadUserByUsername方法,在里面自定义我们获取用户的方式,一般是自己写查询数据库的逻辑。在AbstractUserDetailsAuthenticationProvider 中我们成功获取到了UserDetails对象我们就可以进行认证了:
SpringBoot整合SpringSecurity+JWT+Redis实现前后端分离认证授权 - 认证流程_第9张图片

说明: 在上图中,我们可以看到认证校验分为 前校验、附加校验和后校验,如果任何一个校验出错,就会抛出相应的异常。所有校验都通过后,调用
createSuccessAuthentication() 返回认证信息。

在这里插入图片描述
SpringBoot整合SpringSecurity+JWT+Redis实现前后端分离认证授权 - 认证流程_第10张图片

4. 至此认证信息就被传递回 UsernamePasswordAuthenticationFilter 中,在 UsernamePasswordAuthenticationFilter 的父类 AbstractAuthenticationProcessingFilter 的 doFilter() 中,会根据认证的成功或者失败调用相应的 handler:

SpringBoot整合SpringSecurity+JWT+Redis实现前后端分离认证授权 - 认证流程_第11张图片
5. successfulAuthentication()方法中:

SpringBoot整合SpringSecurity+JWT+Redis实现前后端分离认证授权 - 认证流程_第12张图片
其实就是在这里将认证信息放入 Session 中。

查看 SecurityContext 源码,发现内部就是对 Authentication 的封装,提供了 equalshashcodetoString等方法,而SecurityContextHolder 可以理解为线程中的 ThreadLocal

我们知道一个 HTTP 请求和响应都是在一个线程中执行,因此在整个处理的任何一个方法中都可以通过 SecurityContextHolder.getContext() 来取得存放进去的认证信息。

从 Session 中对认证信息的处理由 SecurityContextPersistenceFilter 来处理,它位于 Spring Security 过滤器链的最前面,它的主要作用是:

  • 当请求时,检查 Session 中是否存在 SecurityContext,如果有将其放入到线程中。
  • 当响应时,检查线程中是否存在 SecurityContext,如果有将其放入到 Session 中。

SpringBoot整合SpringSecurity+JWT+Redis实现前后端分离认证授权 - 认证流程_第13张图片

2.2 获取认证信息

通过调用 SecurityContextHolder.getContext().getAuthentication() 就能够取得认证信息:

@GetMapping("/me")
@ResponseBody
public Object me() {
    return SecurityContextHolder.getContext().getAuthentication();
}

3. 总结

以上便是SpringSecurity的认证流程,后续会根据这个流程去改造整合进我们自己项目

你可能感兴趣的:(SpringSecurity,spring,boot,java,spring,后端,intellij-idea)