我有一个授权服务器和一个资源服务器。我正在授权服务器上创建访问令牌,并尝试使用 oauth2 中的 RemoteTokenServices 在资源服务器上使用它,该服务在授权服务器内部命中"/oauth/check_token",在那里它只检查令牌是否存在及其到期时间。但它不会根据给定的终结点检查角色/作用域,也不会针对access_token检查角色/作用域。
@FrameworkEndpoint
public class CheckTokenEndpoint {
@RequestMapping(value = "/oauth/check_token")
@ResponseBody
public Map<String, ?> checkToken(@RequestParam("token") String value) {
OAuth2AccessToken token = resourceServerTokenServices.readAccessToken(value);
if (token == null) {
throw new InvalidTokenException("Token was not recognised");
}
if (token.isExpired()) {
throw new InvalidTokenException("Token has expired");
}
OAuth2Authentication authentication = resourceServerTokenServices.loadAuthentication(token.getValue());
Map<String, ?> response = accessTokenConverter.convertAccessToken(token, authentication);
return response;
}
}
上面的代码片段来自CheckTokenEndpoint.java。有没有办法实现基于角色/范围的授权?
如果其他人在使用基于 XML 的配置JWT
令牌实现时遇到类似的问题,我已经通过以下方式解决了它
哦,我关于如何使用基于 XML 的配置实现 Spring OAuth2 的详细文章可以在这里找到
一些假设
- 您正在使用具有自定义声明的 JWT 令牌
- 您已经提供了
JwtAccessTokenConvertor
的自定义实现,而该实现又实现了TokenEnhancer
接口(随意实现AccessTokenConvertor和TokenEnhancer接口,而无需使用JwtAccessTokenConvertor) - 您正在使用基于 XML 的配置
仔细观察CheckTokenEndpoint
源代码会发现以下内容
private AccessTokenConverter accessTokenConverter = new DefaultAccessTokenConverter();
而看DefaultAccessTokenConvertor
的源代码,是AccessTokenConvertor
接口的默认实现,基本上有以下合约
Map<String, ?> convertAccessToken(OAuth2AccessToken token, OAuth2Authentication authentication);
OAuth2AccessToken extractAccessToken(String value, Map<String, ?> map);
OAuth2Authentication extractAuthentication(Map<String, ?> map);
就我而言,我使用了 JWT 令牌,这意味着我传递给 /oauth/token_check
终结点的令牌值是已签名的(使用 RSA 密钥对)JWT,TokenCheckEndpoint
将执行一些检查,例如
- 检查令牌是否在数据库(oauth_access_token表中),这不适用于 JWT 实现,因为它们不一定存储在数据库中
- 首先检查其 JWT 令牌是否有效
- 检查令牌的签名是否正确且未被篡改
- 检查它是否未过期
- 我不知道的其他检查
除了上述内容之外,我还需要检查自定义声明(例如范围(即基本上是角色及其关联的权限)在数据库中是否相同(确保自颁发令牌以来角色未更改)。
根据我的调试,当命中/oauth/check_token
端点时,将分别调用extractAuthentication
方法后跟extractAccessToken
(至少在 JWT 实现中)。
由于我已经扩展了JwtAccessTokenConvertor
(这反过来又实现了AccessTokenConvertor
和TokenEnhancer
接口),以便通过覆盖增强方法来增强我的JWT令牌以向其添加自定义声明(即范围),
@Component
public class MyJwtAccessTokenConvertor extends JwtAccessTokenConverter {
@Override
public OAuth2AccessToken enhance(OAuth2AccessToken accessToken, OAuth2Authentication authentication) {
DefaultOAuth2AccessToken result = new DefaultOAuth2AccessToken(accessToken);
//enhance the token with custom claims (i.e. user role scope)
//then return it
return result;
}
@Override
public OAuth2AccessToken extractAccessToken(String value, Map<String, ?> map) {
OAuth2AccessToken mytoken = tokenConverter.extractAccessToken(value, map);
/* validate the custom claims of token i.e. user role scopes
* and if any issue throw an exception
*/
return token;
}
}
我可以轻松验证 JWT 访问令牌是否在 extractAccessToken
方法中具有所需的用户角色作用域。如果我检测到任何违规行为,我会抛出InvalidTokenException
(也可以是自定义异常)。