Spring Security-5-认证流程梳理

前面的文章中首先分析了认证流程的源码,然后我们又实现了自己的登录流程以及一些自定义的处理,下面再来梳理一下这些认证的流程

认证

这里我们之前就已经分析过认证流程了,这里再坐下补充以及回顾,先看下图:

image

首先是进到了 UsernamePasswordAuthenticationFilter, 然后这个里面生成了一个没有经过认证的 Authentication 对象, 然后是调用 AuthenticationManager 找到处理当前登录请求的 AuthenticationProvider, 然后通过 UserDetailsService 做用户的验证(密码等), 然后组装返回一个已认证的 Authentication 对象

这部分的源码之前已经说过了,这里就不再看了

认证成功/失败处理

UsernamePasswordAuthenticationFilter 返回 Authentication 对象之后,会进入到 AbstractAuthenticationProcessingFilter 这个 filter 里面, 看一下源码
image

然后这里主要是判断是否登录成功, 在catch块里面都是调用的认证失败的处理, 然后最后是调用的认证成功的处理

分别看一下这两个方法的源码

image

image

这里每个方法的最后一行,就是去调用我们的自定义的成功/失败的处理

认证结果如何在多个请求之间共享

认证完成之后,那认证结果是如何在多个请求中共享的,一般都是在登录成功之后放到session里面,我们详细的看一下这个认证成功后调用的方法

image

SecurityContext

可以看到这里把认证结果放到了 SecurityContext 里面,先来看下面这个图:
image

认证成功之后,先把认证结果放到了一个 SecurityContext 里面,这个是个接口,实际的实现类是 SecurityContextImpl,看一下源码
image

里面包装了Authentication 主要就是重写了 equals 还有 hashCode, 保证Authentication的唯一性

SecurityContextHolder

然后,是把这个放到了一个 SecurityContextHolder 里面,这个类实际上对 ThreadLocal 的一个封装,可以在不同方法之间进行通信,我们可以简单理解为线程级别的一个全局变量.因此可以在同一个线程中的不同方法中获取到认证信息

SecurityContextPersistenceFilter

最后一步是经过 SecurityContextPersistenceFilter 这个过滤器, 这个也是 security 过滤器链中的一个,位置如下
image

这个过滤器的作用就是 当一个请求来的时候,它会将session中的值传入到该线程中,当请求返回的时候,它会判断该请求线程是否有 SecurityContext, 如果有它会将其放入到session中,因此保证了请求结果可以在不同的请求之间共享

获取认证信息

最后来看一下如何获取用户的认证信息,这个有以下几种方式去拿

第一种

新建接口,代码如下:

1
2
3
4
@GetMapping("/me")
public Object me(){
return SecurityContextHolder.getContext().getAuthentication();
}

第二种

1
2
3
4
@GetMapping("/me")
public Object getMeDetail(Authentication authentication){
return authentication;
}

第三种

1
2
3
4
@GetMapping("/me")
public Object me(@AuthenticationPrincipal UserDetails userDetails){
return userDetails;
}

效果

第一种和第二种方式返回的结果都是一样的,都是返回的 Authentication 对象,如下:
image

第三种方式是只返回了 UserDetails 对象,如下:
image

总结

本文主要是介绍了认证结果共享的原理,就是在认证成功之后放到了一个 SecurityContext 里面,最后通过最外层的过滤器 SecurityContextPersistenceFilter 放到session里面,从而实现认证结果共享

最后就是几种通过接口获取认证后的结果的方法

代码已经上传github,传送门