时间:2021-05-20
SpringSecurity基本原理
在之前的文章《SpringBoot + Spring Security 基本使用及个性化登录配置》中对SpringSecurity进行了简单的使用介绍,基本上都是对于接口的介绍以及功能的实现。 这一篇文章尝试从源码的角度来上对用户认证流程做一个简单的分析。
在具体分析之前,我们可以先看看SpringSecurity的大概原理:
SpringSecurity基本原理
其实比较简单,主要是通过一系列的Filter对请求进行拦截处理。
认证处理流程说明
我们直接来看UsernamePasswordAuthenticationFilter类,
public class UsernamePasswordAuthenticationFilter extends AbstractAuthenticationProcessingFilter // 登录请求认证 public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException { // 判断是否是POST请求 if (this.postOnly && !request.getMethod().equals("POST")) { throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod()); } else { // 获取用户,密码 String username = this.obtainUsername(request); String password = this.obtainPassword(request); if (username == null) { username = ""; } if (password == null) { password = ""; } username = username.trim(); // 生成Token, UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(username, password); this.setDetails(request, authRequest); // 进一步验证 return this.getAuthenticationManager().authenticate(authRequest); } }}在attemptAuthentication方法中,主要是进行username和password请求值的获取,然后再生成一个UsernamePasswordAuthenticationToken 对象,进行进一步的验证。
不过我们可以先看看UsernamePasswordAuthenticationToken 的构造方法
public UsernamePasswordAuthenticationToken(Object principal, Object credentials) { // 设置空的权限 super((Collection)null); this.principal = principal; this.credentials = credentials; // 设置是否通过了校验 this.setAuthenticated(false);}其实UsernamePasswordAuthenticationToken是继承于Authentication,该对象在上一篇文章中有提到过,它是处理登录成功回调方法中的一个参数,里面包含了用户信息、请求信息等参数。
所以接下来我们看
this.getAuthenticationManager().authenticate(authRequest);这里有一个AuthenticationManager,但是真正调用的是ProviderManager。
public class ProviderManager implements AuthenticationManager, MessageSourceAware, InitializingBean { public Authentication authenticate(Authentication authentication) throws AuthenticationException { Class<? extends Authentication> toTest = authentication.getClass(); AuthenticationException lastException = null; Authentication result = null; boolean debug = logger.isDebugEnabled(); Iterator var6 = this.getProviders().iterator(); while(var6.hasNext()) { AuthenticationProvider provider = (AuthenticationProvider)var6.next(); // 1.判断是否有provider支持该Authentication if (provider.supports(toTest)) { // 2. 真正的逻辑判断 result = provider.authenticate(authentication); } }}这里的两次对UserDetails的检查,主要就是通过它的四个返回boolean类型的方法。
经过信息的校验之后,通过UsernamePasswordAuthenticationToken的构造方法,返回了一个经过认证的Authentication。
拿到经过认证的Authentication之后,会再去调用successHandler。或者未通过认证,去调用failureHandler。
认证结果如何在多个请求之间共享
再完成了用户认证处理流程之后,我们思考一下是如何在多个请求之间共享这个认证结果的呢?
因为没有做关于这方面的配置,所以可以联想到默认的方式应该是在session中存入了认证结果。
那么是什么时候存放入session中的呢?
我们可以接着认证流程的源码往后看,在通过attemptAuthentication方法后,如果认证成功,会调用successfulAuthentication,该方法中,不仅调用了successHandler,还有一行比较重要的代码
SecurityContextHolder.getContext().setAuthentication(authResult);SecurityContextHolder是对于ThreadLocal的封装。 ThreadLocal是一个线程内部的数据存储类,通过它可以在指定的线程中存储数据,数据存储以后,只有在指定线程中可以获取到存储的数据,对于其他线程来说则无法获取到数据。 更多的关于ThreadLocal的原理可以看看我以前的文章。
一般来说同一个接口的请求和返回,都会是在一个线程中完成的。我们在SecurityContextHolder中放入了authResult,再其他地方也可以取出来的。
最后就是在SecurityContextPersistenceFilter中取出了authResult,并存入了session
SecurityContextPersistenceFilter也是一个过滤器,它处于整个Security过滤器链的最前方,也就是说开始验证的时候是最先通过该过滤器,验证完成之后是最后通过。
获取认证用户信息
/** * 获取当前登录的用户 * @return 完整的Authentication */@GetMapping("/me1")public Object currentUser() { return SecurityContextHolder.getContext().getAuthentication();}@GetMapping("/me2")public Object currentUser(Authentication authentication) { return authentication;}/** * @param userDetails * @return 只包含了userDetails */@GetMapping("/me3")public Object cuurentUser(@AuthenticationPrincipal UserDetails userDetails) { return userDetails;}以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
声明:本页内容来源网络,仅供用户参考;我单位不保证亦不表示资料全面及准确无误,也不保证亦不表示这些资料为最新信息,如因任何原因,本网内容或者用户因倚赖本网内容造成任何损失或损害,我单位将不会负任何法律责任。如涉及版权问题,请提交至online#300.cn邮箱联系删除。
java中SpringSecurity的实例详解springsecurity是一个多方面的安全认证框架,提供了基于JavaEE规范的完整的安全认证解决方案。并且
本文实例讲述了Java开发之springsecurity实现基于MongoDB的认证功能。分享给大家供大家参考,具体如下:springsecurity对基于数据
1简介在之前的文章《Springboot集成SpringSecurity实现JWT认证》讲解了如何在传统的Web项目中整合SpringSecurity和JWT,
springsecurity是一个很大的模块,本文中只涉及到了自定义参数的认证。springsecurity默认的验证参数只有username和password
springsecurity简介springsecurity的核心功能主要包括:认证(你是谁)授权(你能干什么)攻击防护(防止伪造身份)其核心就是一组过滤器链,