明确目标
还记得我们刚了解OAuth时说的,它默认只有四种认证模式,那么如果我们想用短信验证或者第三方登录验证的模式,如何自定义授权模式并嫁接到认证服务器中呢?
即我们自己实现认证方式,然后使用Security造好的Token生成存放校验逻辑进行Token管理
为了达到这个目的,我们需要对SpringSecurity OAuth源码进行解析
源码解析
TokenEndPoint
首先,在我们上一章中,获取令牌的方式是向/oauth/token
发送post请求,根据我们对springboot的了解,这个是由EndPoint
端点控制的,所以我们直接取看TokenEndPoint
源码。
1 | public class TokenEndpoint extends AbstractEndpoint { |
看完源码,我们可以发生请求试试,这里我们使用密码模式,因为比较简单。
可以看到,就是我们请求中的信息,我们接着往下看生成Token的源码
OAuth2AccessToken token = getTokenGranter().grant(tokenRequest.getGrantType(), tokenRequest);
生成Token
根据grantType找到正确的Token生成器
首先它会进到TokenGranter
的实现类CompositeTokenGranter
里
1 | public class CompositeTokenGranter implements TokenGranter { |
这里有四种授权模式,和一个RefreshToken
的生成器。
密码模式生成器
因为我们是密码模式,所以使用ClientCredentialsTokenGranter
这个生成器
1 | public class ClientCredentialsTokenGranter extends AbstractTokenGranter { |
这里也是一个中间处理类,具体生成还要往下走
具体实现类为AbstractTokenGranter
1 | public OAuth2AccessToken grant(String grantType, TokenRequest tokenRequest) { |
这里我们先看getAccessToken()
方法,他的实现分为两步
getOAuth2Authentication()
:先对密码进行校验createAccessToken()
:然后再创建成功的令牌
然后我们会发现getAccessToken()
方法是protected
,所以其实实现还是要看他这个子实现类,使用的设计模式是模板模式。
密码认证获取OAuth2Authentication对象
因为我们这里使用的是密码模式,不同的模式其getOAuth2Authentication
方法的实现都是不同的,我们先看看ResourceOwnerPasswordTokenGranter
的实现
1 |
|
这里认证流程其实我们在最开始学习表单登录的时候已经看过了,就是对密码进行校验,如果成功创建一个授权的Authorization
,这里还会将OAuth2Request
和Authentication
进行封装生成OAuth2Authentication
真正的生成逻辑
接着我们就要看createAccessToken()
方法了,实现类为DefaultTokenServices
1 |
|
TokenStore
的实现有多种,这里我们还是存在内存中的
最重要的生成Token的代码终于要来了,也是这个类的私有方法
1 | private OAuth2AccessToken createAccessToken(OAuth2Authentication authentication, OAuth2RefreshToken refreshToken) { |
看完之后是不是索然无味了,其实就是使用UUID
生成的,我们在之前看到返回accessToken
的样式时其实就能猜到。
总结流程
从TokenEndpoint
开始,我们总结了以上步骤
TokenEndpoint
为获取Token的API入口- 通过
ClientDetailsService
获取请求中的第三方应用信息ClientDetails
,如client-id
,client-secret
,scope
- 然后根据
ClientDetails
和请求中的信息(grantType
,认证验证码等)组装成TokenRequest
对象 - 使用
TokenGranter
生成Token,根据不同的grantType
使用正确的授权模式生成 - 在生成Token逻辑中,首先会对密码进行验证,验证通过会将
OAuth2Request
和Authorization
(封装了用户信息)组装成OAuth2Authorization
对象 - 最后使用
DefaultTokenServices
生成Token,将Token存储,并对Token增强