撤销 JWT Oauth2 刷新令牌

Posted

技术标签:

【中文标题】撤销 JWT Oauth2 刷新令牌【英文标题】:Revoke JWT Oauth2 Refresh Token 【发布时间】:2015-12-13 13:46:37 【问题描述】:

我正在尝试找到一种方法来使用 vanilla Spring 实现和 JwtTokenStore 来撤销 Oauth2 JWT 刷新令牌。

首先:有人可以确认没有类似于 /oauth/token 的 API 可以让我撤销刷新令牌吗?

我想添加一个自定义 API,该 API 将沿以下几行删除刷新令牌:

OAuth2RefreshToken oauth2RefreshToken=tokenStore.readRefreshToken(refreshToken);
tokenStore.removeRefreshToken(oauth2RefreshToken);

现在,查看 JwtTokenStore,我注意到它使用 ApprovalStore。所以我继续为我的 JwtTokenStore 提供了一个 InMemoryApprovalStore。我的 JwtTokenStore 实例化如下所示:

@Bean
protected JwtAccessTokenConverter jwtTokenEnhancer() 
    JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
    converter.setSigningKey("123456");
    return converter;


@Bean
public JwtTokenStore getTokenStore()
    tokenStore= new JwtTokenStore(jwtTokenEnhancer());
    tokenStore.setApprovalStore(new InMemoryApprovalStore());
    tokenStore.setTokenEnhancer(jwtTokenEnhancer());
    return tokenStore;
;

结果:没有 InMemoryApprovalStore,我可以毫无问题地验证用户和刷新令牌。但是,只要将 InMemoryApprovalStore 添加到令牌存储区,我就会开始收到以下错误消息:

"error":"invalid_grant","error_description":"Invalid refresh token: eyJhbGciOiJIUzI1NiJ9.eyJleHAiOjE0NDUwMjQ2MTcsInVzZXJfbmFtZSI6IjYzZjIyYjZlLWU5MGUtNDFjYS1iYzJlLTBmZTgzNmY3MTQ2NyIsImF1dGhvcml0aWVzIjpbIlJPTEVfQURNSU4iLCJST0xFX1VTRVIiXSwianRpIjoiMjgwMDgwNWQtMjk1Zi00ZDQzLWI2NTYtMDNlZWYwMWFkMjg0IiwiY2xpZW50X2lkIjoid2ViLWNsaWVudCIsInNjb3BlIjpbInJlYWQiLCJ3cml0ZSIsInRydXN0Il19.BPC0HqLYjWGM0IFjvsUGGKQ9dyIXSXwMhraCVFIxD0U"

因此,我的第二个问题是撤销刷新令牌的正确方法是什么?

编辑:我发现 following thread 表明 ApprovalStore 确实是撤销 JWT 令牌的方法。我现在只需要了解如何正确使用它们。

【问题讨论】:

【参考方案1】:

首先:有人可以确认没有类似于 /oauth/token 的 API 可以让我撤销刷新令牌吗?

Confirmed.

您不需要定义JwtTokenStore bean,spring 会使用AuthorizationServerEndpointsConfigurer 为您创建它

private TokenStore tokenStore() 
    if (tokenStore == null) 
        if (accessTokenConverter() instanceof JwtAccessTokenConverter) 
            this.tokenStore = new JwtTokenStore((JwtAccessTokenConverter) accessTokenConverter());
        
        else 
            this.tokenStore = new InMemoryTokenStore();
        
    
    return this.tokenStore;


private ApprovalStore approvalStore() 
    if (approvalStore == null && tokenStore() != null && !isApprovalStoreDisabled()) 
        TokenApprovalStore tokenApprovalStore = new TokenApprovalStore();
        tokenApprovalStore.setTokenStore(tokenStore());
        this.approvalStore = tokenApprovalStore;
    
    return this.approvalStore;

因此,我的第二个问题是撤销刷新令牌的正确方法是什么?

撤销对令牌的批准,这是由JwtTokenStore使用的

private void remove(String token) 
    if (approvalStore != null) 
        OAuth2Authentication auth = readAuthentication(token);
        String clientId = auth.getOAuth2Request().getClientId();
        Authentication user = auth.getUserAuthentication();
        if (user != null) 
            Collection<Approval> approvals = new ArrayList<Approval>();
            for (String scope : auth.getOAuth2Request().getScope()) 
                approvals.add(new Approval(user.getName(), clientId, scope, new Date(), ApprovalStatus.APPROVED));
            
            approvalStore.revokeApprovals(approvals);
        
    

【讨论】:

TokenApprovalStore 并没有真正让您撤销刷新令牌。至少不使用 JWTTokenStore。 JWTTokenStore.removeRefreshToken 调用 tokenStore.revokeApprovals。而这个方法又会调用tokenStore.findTokensByClientIdAndUserName,在JWTTokenStore的情况下总是返回一个空集。 是的,你是对的,但概念是一样的,使用ApprovalStore,实现由你决定 如果我正确理解审批流程,撤销审批意味着客户端应用程序不再被授权“使用”该帐户,因此用户/客户端的所有访问和刷新令牌都将被拒绝。但是,如果您只想撤销单个刷新令牌,那不是太严格了吗?撤销批准意味着用户不能再做任何事情。另外,一旦用户稍后再次批准客户端,所有访问和刷新令牌都可以再次使用。难道没有办法以不阻止其他访问和刷新令牌的方式撤销刷新令牌吗? @MangEngkus 如果我错了,请纠正我,但这不起作用,因为JwtTokenStore 没有为storeRefreshToken(OAuth2RefreshToken refreshToken, OAuth2Authentication authentication) 提供实现,所以即使使用InMemoryApprovalStore,也不会获得任何批准已添加。 @WillFaithfull 是的,正如我在之前的评论中解释的那样,您可以提供自己的实现

以上是关于撤销 JWT Oauth2 刷新令牌的主要内容,如果未能解决你的问题,请参考以下文章

如何撤销 JWT 令牌?

Oauth2/Openid 连接。如何撤销未知的访问/刷新令牌

如何基于使用 Oauth2 协议的身份验证改进 JWT 访问令牌和刷新令牌?

Google API OAuth2 刷新令牌突然被撤销

安全性 - JWT 和 Oauth2(刷新令牌)

撤销/使 .boto 文件(gsutil config)中生成的 oauth2 刷新令牌无效