目录
1.回执
回执版本一(默认)
回执版本二
2.回执DefaultOAuth2AccessToken类图
3.请求/oauth/token流程
3.1.CompositeTokenGranter.grant
3.1.1根据前端传参的grantType,匹配数组tokenGranters中的对应类型
3.1.2.validateGrantType看ClientDetails是否有对应的grantType的权限
3.1.3.获取用户token
3.2.返回token
4.两个版本回执的原因
4.1.OAuth2AccessToken的序列化方式有两种
4.2.版本1回执OAuth2AccessTokenJackson2Serializer
4.3.版本2回执OAuth2AccessTokenJackson1Serializer
4.4.回执版本变化的原因
4.5.fastJSON使用默认回执数据结构
* {
* "access_token": "eeff86b8-66d5-428c-9c2b-9d1cce4d502a",
* "token_type": "bearer",
* "refresh_token": "7cc00001-ba52-473f-9c49-ee63f2ca1a0c",
* "expires_in": 1799,
* "scope": "read write trust"
* }
DefaultOAuth2AccessToken
* {
* "additionalInformation": {},
* "expiration": "2020-01-13 16:52:45",
* "expired": false,
* "expiresIn": 1598,
* "refreshToken": {
* "expiration": "2020-01-13 17:22:45",
* "value": "a8ddb0a0-5872-4b70-aa12-3f0a4c4e9247"
* },
* "scope": [
* "read",
* "write",
* "trust"
* ],
* "tokenType": "bearer",
* "value": "2b576b11-cad8-4756-89e6-7090023407b2"
*}
granter.grant()方法如果grantType不匹配,就直接返回null。如果匹配就validateGrantType
这个set的值,是我们根据用户去在数据库保存的。
先从tokenStore获取有没有token,如果token存在,则校验是否过期,过期了则先清除刷新token,再清除该token。
有5种getAccessToken方式,我们如果用的是数据库,就是JdbcTokenStore
如果没有已经存在的token,则新建
新建的token类型正是DefaultOAuth2AccessToken
返回结果会通过通用的项目的WebMvcConfigurerAdapter进行序列化(因为实际上也是http请求的回执)
OAuth2AccessTokenJackson1Serializer
OAuth2AccessTokenJackson2Serializer
{
"access_token": "2de139d5-4b8e-49d0-baf4-1f37a9b3796d",
"token_type": "bearer",
"refresh_token": "f35dae51-c6d3-4a10-86b7-5f417834baa4",
"expires_in": 1793,
"scope": "read write trust"
}
{
"additionalInformation": {},
"expiration": "2020-01-14 11:07:49",
"expired": false,
"expiresIn": 1798,
"refreshToken": {
"expiration": "2020-01-14 11:37:49",
"value": "47ad8c7b-61f9-41db-bb7c-8a020efc38a1"
},
"scope": [
"read",
"write",
"trust"
],
"tokenType": "bearer",
"value": "6a49bff9-2f70-41cb-b83b-209294c45c0c"
}
Spring Security Oauth2 返回非标准数据结构 OAuth2AccessToken 序列化问题_yuelangyc的专栏-CSDN博客 https://blog.csdn.net/yuelangyc/article/details/88235639
如文章所述,如果自定义了消息处理,覆盖了默认的消息处理器。
使用 fastjson 时, spring security oauth2 获取 token 格式变化 · Issue #1640 · alibaba/fastjson https://github.com/alibaba/fastjson/issues/1640
针对fastjson,确实存在自定义fastjson消息处理器时,出现回执版本变化。
参考上面的文章
你需要自行写个HttpMessageConverter来转换OAuth2AccessToken,fastjson本身也意识到这个问题,但是FormOAuth2AccessTokenMessageConverter这个类的writeInternal方法没有进行实现,你需要自行实现转换
public class OAuth2AccessTokenMessageConverter extends AbstractHttpMessageConverter {
private final FastJsonHttpMessageConverter delegateMessageConverter;
public OAuth2AccessTokenMessageConverter() {
super(MediaType.APPLICATION_JSON);
this.delegateMessageConverter = new FastJsonHttpMessageConverter();
}
@Override
protected boolean supports(Class> clazz) {
return OAuth2AccessToken.class.isAssignableFrom(clazz);
}
@Override
protected OAuth2AccessToken readInternal(Class extends OAuth2AccessToken> clazz, HttpInputMessage inputMessage)
throws IOException, HttpMessageNotReadableException {
throw new UnsupportedOperationException(
"This converter is only used for converting from externally acquired form data");
}
@Override
protected void writeInternal(OAuth2AccessToken accessToken, HttpOutputMessage outputMessage) throws IOException,
HttpMessageNotWritableException {
Map data = new HashMap<>(8);
data.put(OAuth2AccessToken.ACCESS_TOKEN, accessToken.getValue());
data.put(OAuth2AccessToken.TOKEN_TYPE, accessToken.getTokenType());
data.put(OAuth2AccessToken.EXPIRES_IN, accessToken.getExpiresIn());
data.put(OAuth2AccessToken.SCOPE, String.join(" ", accessToken.getScope()));
OAuth2RefreshToken refreshToken = accessToken.getRefreshToken();
if (Objects.nonNull(refreshToken)) {
data.put(OAuth2AccessToken.REFRESH_TOKEN, refreshToken.getValue());
}
delegateMessageConverter.write(data, MediaType.APPLICATION_JSON, outputMessage);
}
}
注意:上面问题回答针对的只是OAuth2AccessToken,所以实际上,如果我们的项目还有其他的http请求需要处理,则需要修改上面的转换器,只处理token的回执保持兼容,其他请求的回执仍然保持原样
public class OAuth2AccessTokenMessageConverter extends AbstractHttpMessageConverter
加入MessageConverters
@Configuration
public class Oauth2WebMvcConfigurer implements WebMvcConfigurer {
@Override
public void configureMessageConverters(List> converters) {
converters.add(0, new OAuth2AccessTokenMessageConverter());
}
}
你可以参考OAuth2AccessToken这个序列化类OAuth2AccessTokenJackson2Serializer进行编写相应的代码