Spring Security认证过程

类图

在这里插入图片描述

一、用户认证流程

上节中提到Spring Security核心就是一系列的过滤器链,当一个请求来的时候,首先要通过过滤器链的校验,校验通过之后才会访问用户各种信息。
这里要说明的是在过滤器的最前端有一个SecurityContextPersistenceFilter,当请求进来和返回的时候都会经过这个过滤器,它主要存放用户的认证信息。这里先简单提一下,后面会详解。
在这里插入图片描述

当用户发送登录请求的时候,首先进入到UsernamePasswordAuthenticationFilter中进行校验。
在这里插入图片描述
打断点发送登录请求进入源码中,我们会发现它会进入到UsernamePasswordAuthenticationFilter,在该类中,有一个attemptAuthentication方法在这个方法中,会获取用户的username以及password参数的信息,然后使用构造器new UsernamePasswordAuthenticationToken(username, password)封装为一个UsernamePasswordAuthenticationToken对象,在这个构造器内部会将对应的信息赋值给各自的本地变量,并且会调用父类AbstractAuthenticationToken构造器(这个父类的构造器后面会介绍到),传一个null值进去,为什么是null呢?因为刚开始并没有认证,因此用户没有任何权限,并且设置没有认证的信息(setAuthenticated(false)),最后会进入AuthenticationManager接口的实现类ProviderManager中。
在这里插入图片描述
request里边存放的是请求的信息
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在ProviderManager这个实现类中,它会调用AuthenticationProvider接口的实现类获取用户的信息,用户的信息权限的验证就在该类中校验。进入ProviderManager类中调用authenticate(Authentication authentication)方法,它通过AuthenticationProvider实现类获取用户的登录的方式后会有一个for循环遍历它是否支持这种登录方式,具体的登录方式有表单登录,qq登录,微信登录等。如果都不支持它会结束for循环,如果支持则会进入AuthenticationProvider接口的抽象实现类AbstractUserDetailsAuthenticationProvider中调用 authenticate(Authentication authentication)方法对用户的身份进入校验。

ProviderManager

在这里插入图片描述
进入抽象类AbstractUserDetailsAuthenticationProvider的内部的authenticate方法之后,先会判断user是否为空,这个user是UserDetail的对象,如果为空,表示还没有认证,就需要调用retrieveUser方法去获取用户的信息,这个方法是抽象类AbstractUserDetailsAuthenticationProvider的扩展类DaoAuthenticationProvider的一个方法。
UserDetailsService从数据库获取用户数据,封装成UserDetails返回

AbstractUserDetailsAuthenticationProvider

在这里插入图片描述
在这里插入图片描述
调用AuthenticationProvider的authenicate方法,实际上是调用其实现类AbstractUserDetailsAuthenticationProvider中的authenicate方法,authenticate再调用retrieveUser方法去获取用户信息验证

DaoAuthenticationProvider

DaoAuthenticationProvider继承了AbstractUserDetailsAuthenticationProvider类,并且实现了retrieveUser方法
调用UserDetailsService这个接口的实现类的loadUserByUsername方法去获取用户信息,而这里我自己编写了实现类MyUserDetail类,在这个实现类中,我们可以编写自己的逻辑,从数据库中获取用户密码等权限信息返回。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
如果拿到了用户信息user,如果没有拿到则会抛出异常
1.perAuthenticationChecks—预检查,检查三个布尔异常,密码是否为空等等
2.additionalAuthenticationChecks附加检查,用passwordEncoder校验当前密码是否匹配
3.如果都通过了,还有一个postAuthenticationChecks—后检查第四个布尔
三个检查都通过,则用户认证是成功的
当三个检查都通过时,最后构建一个createSuccessAuthentication

  • true,//账号可用
  • true,//账号不过期
  • true,//密码不过期
  • true,//账号没有锁定

在拿到用户的信息后,返回到AbstractUserDetailsAuthenticationProvider类中调用**createSuccessAuthentication(principalToReturn, authentication, user)**方法,在该方法中会调用三个参数的UsernamePasswordAuthenticationToken构造器,不同于前面调用两个参数的,因为这里已经验证了用户的信息和权限,因此不再是给父类构造器中传null值了,而是用户的权限集合,并且设置认证通过(setAuthenticated(true)),
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
有三个参数,因为现在已经做了登录,认证已经成功了,已经拿到UserDetails,从UserDetails里可以获得用户的权限,所以super(authorities)
在UsernamePasswordAuthenticationToken的父类中,它会检查用的权限,如果有一个为null,表示权限没有相应的权限,抛出异常。
在这里插入图片描述
然后在createSuccessAuthentication方法返回后回到ProvioderManager的authenticate方法中返回result,最后回到UsernamePasswordAuthenticationFilter的刚开始进入的attemptAuthentication方法中返回。
在这里插入图片描述
在这里插入图片描述
认证成功后就回去调用successfulAuthentication,也就是调用successHandler登录成功处理器
在这里插入图片描述
如果认证过程中有异常,则会调用failureHandler认证失败处理器

总结:
通过上面的源码我们已经深入源码了解到用户的具体认证流程。这里简单总结一下,首先当用户发送请求的时候,会进入到UsernamePasswordAuthenticationFilter中得到一个UsernamePasswordAuthenticationToken,它其实相当于一个令牌,不过还没有经过认证,然后调用AuthenticationManager的实现类ProviderManager中判断登录方式是否支持,如果支持,则会调用AuthenticationProvider接口的抽象实现类AbstractUserDetailsAuthenticationProvider中调用它的扩展类DaoAuthenticationProvider中获取我们自己实现的MyUserDetails类获取用户密码进行用户身份验证,然后返回该对象,设置UsernamePasswordAuthenticationToken这个令牌认证通过,用户身份校验成功。

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

下面我们来看看用户在通过身份校验之后,是如何将认证结果在多个请求中共享的呢?肯定是放入session当中的。先来看看流程图。
在这里插入图片描述
身份认证成功后,最后在UsernamePasswordAuthenticationFilter返回后会进入一个AbstractAuthenticationProcessingFilter类中调用successfulAuthentication方法中,这个方法最后会返回我们自己定义的登录成功处理器handler,在返回之前,它会调用SecurityContext,最后将认证的结果放入SecurityContextHolder中,SecurityContext类很简单,重写了equals方法和hascode方法,保证了authentication的唯一性。SecurityContextHolder类实际上对ThreadLocal的一个封装,可以在不同方法之间进行通信,我们可以简单理解为线程级别的一个全局变量。因此可以在同一个线程中的不同方法中获取到认证信息。最后会被SecurityContextPersistenceFilter过滤器使用,这个过滤器的作用是什么呢?当一个请求来的时候,它会将session中的值传入到该线程中,当请求返回的时候,它会判断该请求线程是否有SecurityContext,如果有它会将其放入到session中,因此保证了请求结果可以在不同的请求之间共享。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

三、获取认证用户信息

如果我们需要获取用的校验过的所有信息,该如何获取呢?上面我们知道了会将校验结果放入session中,因此,我们可以通过session获取。

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

@GetMapping("/me1")
    public Object getMeDetail(Authentication authentication){
   
        return authentication;
    }

在登录成功之后,上面有两种方式来获取,访问上面的请求,就会获取用户全部的校验信息,包括ip地址等信息。
在这里插入图片描述
如果我们只想获取用户名和密码以及它的权限,不需要ip地址等太多的信息可以使用下面的方式来获取信息。

@GetMapping(
  • 8
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
Spring Security认证流程可以简要描述如下: 1. 当一个请求进入系统时,会经过一个过滤器链,其中包括一个实现了AbstractAuthenticationProcessingFilter的过滤器。 2. 这个过滤器会首先判断请求的URI是否需要认证,如果需要认证,则执行attemptAuthentication方法进行认证。 3. attemptAuthentication方法会调用AuthenticationManager进行认证,AuthenticationManager是一个接口,具体的实现类是ProviderManager。 4. ProviderManager内部包了一个List<AuthenticationProvider>对象,通过AuthenticationProvider接口的实现类来扩展不同的认证提供者。 5. 在认证过程中,AuthenticationManager会依次调用每个AuthenticationProvider的authenticate方法进行认证。 6. 如果认证成功,会将认证后的Authentication对象存放到SecurityContext中。 7. 如果认证失败,会通过认证失败处理器AuthenticationFailureHandler进行处理。 8. 认证成功后,会执行successfulAuthentication方法,将已认证的Authentication存放到SecurityContext中。 9. 这样,下一个请求进来时,系统就能知道该请求是否已经通过认证。 总结起来,Spring Security认证流程包括了过滤器链、认证管理器、认证提供者和认证失败处理器等组件,通过这些组件的协作,实现了对请求的认证和授权。\[1\]\[2\]\[3\] #### 引用[.reference_title] - *1* *2* [SpringSecurity认证流程分析](https://blog.csdn.net/chisuisi5702/article/details/126281839)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [Spring Security认证过程](https://blog.csdn.net/weixin_38927257/article/details/102960752)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值