springSecurity及springOAuth2源码解析

springSecurity及springOAuth2源码解析


前言

在DEBUG分析springOAuth2的登录源码前,此处先列出springSecurity与OAuth2的定义。
springSecurity定义:
Spring Security是一个能够为基于Spring的企业应用系统提供声明式的安全访问控制解决方案的安全框架。它提供了一组可以在Spring应用上下文中配置的Bean,充分利用了Spring IoC,DI(控制反转Inversion of Control ,DI:Dependency Injection 依赖注入)和AOP(面向切面编程)功能,为应用系统提供声明式的安全访问控制功能,减少了为企业系统安全控制编写大量重复代码的工作。

OAuth2.0定义:
OAuth2.0是OAuth协议的延续版本,但不向前兼容OAuth 1.0(即完全废止了OAuth1.0)。 OAuth 2.0关注客户端开发者的简易性。要么通过组织在资源拥有者和HTTP服务商之间的被批准的交互动作代表用户,要么允许第三方应用代表用户获得访问的权限。同时为Web应用,桌面应用和手机,和起居室设备提供专门的认证流程。

以下是个人理解哈:
springSecurity是提供认证授权的安全框架,可能考虑的场景没有那么全。然后OAuth2.0对所有场景的认证流程做了个标准定义。之后spring对OAuth2.0协议进行了实现。
因为接触到的认证场景较少,所以很难理解OAuth2.0协议的精髓,先大概了解下吧。

此篇文章对springSecurity与springOAuth2框架实现的登录接口/oauth/token【POST】进行DEBUG源码分析。


一、/oauth/token接口代码路径

第一次接触还以为是公司自己写的登录接口呢0.0。后来才知道是spring-security-oauth2 jar包自带的接口。
类:

org.springframework.security.oauth2.provider.endpoint.TokenEndpoint

接口方法:

@RequestMapping(value = {"/oauth/token"}, method = {RequestMethod.POST})
public ResponseEntity<OAuth2AccessToken> postAccessToken(Principal principal, @RequestParam Map<String, String> parameters) throws HttpRequestMethodNotSupportedException 

二、源码分析

以下分析是在如下连接的demo基础上实现的,demo中实现了账号密码以及短信验证码登录方式,此处只分析短信验证码模式(其他模式原理一样)。
使用springSecurity及OAuth2实现多模式登录

1、接口调用

通过postman调用接口。


通过DEBUG查看接口入参:

2、加载配置信息

如下图,通过clientId获取clientId对应的配置信息,包括次clientId支持的认证方式、token有效期等信息。
在这里插入图片描述

3、创建TokenRequest

此处没啥说的,后面就new了一个对象。
在这里插入图片描述

4、认证并生成token

4.1、通过入参确定granter

继续回到/oauth/token接口方法,后面几行校验代码略过。
从DEBUG中可以看到this.getTokenGranter()为CompositeTokenGranter。
在这里插入图片描述
这块是demo中配置granter时初始化的选择,如下图:
在这里插入图片描述
下来咱们分析grant()方法。
在这里插入图片描述
代码很简单,通过循环去判断到底使用哪一个granter去处理。通过入参“grant_type=SMSVerification”,咱们直接就看看SMSVerificationTokenGranter的代码。会发现SMSVerificationTokenGranter 继承自AbstractTokenGranter,而且没有重写AbstractTokenGranter的grant(String grantType, TokenRequest tokenRequest)方法。

public class SMSVerificationTokenGranter extends AbstractTokenGranter

那么咱们就需要看看父类AbstractTokenGranter的grant(String grantType, TokenRequest tokenRequest)方法实现。如下图:
在这里插入图片描述
代码也很简单,判断属性grantType是否和入参一致,一致则准备认证并生成token。
当代码执行到方法的最后一行

return this.getAccessToken(client, tokenRequest);

时,这个时候要注意this指的是AbstractTokenGranter的子类SMSVerificationTokenGranter。

4.2、springSecurity认证

下图这段代码就是认证并生成token的真正开始。先看括号里面的代码执行,我们知道this指的是SMSVerificationTokenGranter。而且demo中的SMSVerificationTokenGranter类重写了方法

getOAuth2Authentication(ClientDetails client, TokenRequest tokenRequest)

在这里插入图片描述
下来就需要跳转到SMSVerificationTokenGranter类DEBUG了。
在这里插入图片描述

这里我们从入参中解析参数并创建SMSVerificationAuthenticationToken对象(这里咱们不讨论为什么要新建SMSVerificationAuthenticationToken这个类,文章最后会附上其他大佬对SpringSecurity框架的API分析文章地址)。
我们可以看到创建的SMSVerificationAuthenticationToken对象中的属性也就是附上了登录入参而已。
下来准备进行短信验证码的认证,从DEBUG中可以看到authenticationManager是WebSecurityConfigurerAdapter中的内部类AuthenticationManagerDelegator。
那么咱们就DEBUG跳过来看AuthenticationManagerDelegator的authenticate(Authentication authentication)方法。
在这里插入图片描述
this.delegate为null,于是通过this.delegateBuilder.getObject()给this.delegate重新赋值。
从DEBUG参数中可以看到为ProviderManager。
那么咱们又要跳到ProviderManager去看ProviderManager中的authenticate(Authentication authentication)方法。
这里ProviderManager管理一系列的provider实现。
在这里插入图片描述这里的toTest就是我们的SMSVerificationAuthenticationToken的Class对象。
通过迭代器遍历所有的provider(有许多是springSecurity默认的)找到我们自己的实现SMSAuthenticationProvider,我们可以看看我们SMSAuthenticationProvider中的supports(Class<?> authentication)方法,如下图:
在这里插入图片描述
下来咱们就要看我们自己provider的认证方法了,毕竟咱们是自定义的认证方式。
在这里插入图片描述
这里可以看到入参为SMSVerificationAuthenticationToken对象,SMSVerificationAuthenticationToken对象中的属性principal为输入的用户名,属性credentials为输入的短信验证码。
这里我写死的短信验证码比较,实际业务中还是要从短信验证码的存储位置取出做比较的。
在这里插入图片描述
这行代码是获取用户信息的。
SMSAuthenticationProvider的初始化是在配置文件WhqSecurityConfig中处理的(demo中给短信验证码方式赋予了新的获取用户的方式),如下图:
在这里插入图片描述
咱们再来看SMSAuthenticationProvider认证方法authenticate(Authentication authentication)最后的代码。这里判断了用户的存在性(实际业务可能还需要做其他判断),最后又重新创建了SMSVerificationAuthenticationToken对象为后面生成token做准备,这里创建对象时构造函数中调用了父类的方法super.setAuthenticated(true),此参数是告诉框架认证通过的标记。如下图:
在这里插入图片描述
代码执行到这里说明我们的认证已经完成了。下来就是要准备生成token了。

4.3、Token生成

现在我们回到SMSVerificationTokenGranter类的getOAuth2Authentication(ClientDetails client, TokenRequest tokenRequest)方法。
当springSecurity认证完成后,返回Authentication对象,如下图:
在这里插入图片描述
认证通过后userAuth参数中principal属性为用户信息,authenticated属性表示认证通过。
方法最后创建OAuth2Authentication对象,属性storedRequest为OAuth2Request对象(后面生成token时从此参数获取相关配置信息,比如token的有效期),属性userAuthentication为springSecurity认证结果,其中包含用户详细信息。
接下来代码执行到AbstractTokenGranter,下图中的this.getOAuth2Authentication(client, tokenRequest)方法执行完成,准备生成Token执行this.tokenServices.createAccessToken。
在这里插入图片描述
DefaultTokenServices类的createAccessToken(OAuth2Authentication authentication)方法源码如下,53行会返回null,于是会执行到70行生成一个UUID的refreshToken。78行准备生成accessToken。
在这里插入图片描述
下来看方法createAccessToken(OAuth2Authentication authentication, OAuth2RefreshToken refreshToken)的源码。
在这里插入图片描述

此方法前面只是创建DefaultOAuth2AccessToken对象并初始化部分参数信息。主要看return语句,从DEBUG信息中我们可以知道return的时候执行的是this.accessTokenEnhancer.enhance(token, authentication)方法。
从配置文件中我们可以知道此处需要执行token增强相关的方法。
在这里插入图片描述
最终会执行demo中JwtTokenEnhancer的enhance(OAuth2AccessToken accessToken, OAuth2Authentication authentication)方法。在此处我们可以将token信息存入redis缓存。这里就没啥可说的了。
在这里插入图片描述
到此处AbstractTokenGranter中的方法getAccessToken(ClientDetails client, TokenRequest tokenRequest)执行完成,token生成完成。
在这里插入图片描述
这个时候再回到我们的登录接口:/oauth/token
将生成的token信息返回给客户端即可。
在这里插入图片描述

5、登录完成

最后看下登录结果:

在这里插入图片描述


总结

以上只是通过DEBUG模式对springOAuth2提供的登录接口/oauth/token(POST)进行分析,大家看到最后可能有点乱。文中有不对的地方希望大家评论指正,感谢!!!
以下文章对springSecurity做了更全面且清晰的分析,包括主要API的介绍、相关的类图、认证流程等。大家看完之后再对自己实际开发的项目进行DEBUG分析应该会更有收获。
Spring Security系列教程11–Spring Security核心API讲解
Spring Security系列教程12–Spring Security认证授权流程
以上两篇文章的作者专门开了个专栏对springSecurity进行讲解。写的不错,值得一看。
SpringSecurity精讲系列

  • 0
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值