在Spring Security中生成JWT时,如何使访问令牌的有效负载与刷新令牌的有效负载不同?

问题描述

虽然我们有解决方案,但我们想知道是否有更好的解决方案,因为我们的方案很丑陋,而且感觉超级错误。那么,有人知道使用Spring Security会有更好的解决方案吗?

问题

我们维护一个用于管理用户帐户的应用程序。登录时,我们生成两个JWT-访问令牌和刷新令牌。我们希望访问令牌的有效负载包含与刷新令牌不同的字段集。例如,如果 access 令牌的有效载荷为:

{
  "a" : "foo","b" : "bar",}

我们希望 刷新 令牌的有效载荷为:

{
  "a" : "foo","x" : "baz",}

我们做什么

我们唯一想到的解决方案是实现一个自定义令牌增强器,该增强器扩展了JwtAccesstokenConverter并覆盖了enhance方法,因此对超类方法内容进行了很小的修改,以控制每个有效载荷的内容。这是代码

public class CustomJwtAccesstokenConverter extends JwtAccesstokenConverter {

  @Override
  public OAuth2Accesstoken enhance(
      OAuth2Accesstoken accesstoken,OAuth2Authentication authentication
  ) {
    DefaultOAuth2Accesstoken result = new DefaultOAuth2Accesstoken(accesstoken);
    Map<String,Object> info = new LinkedHashMap<>(accesstoken.getAdditional@R_393_4045@ion());


    // <custom-code>
    info.remove("x");
    // </custom-code>


    String tokenId = result.getValue();
    if (!info.containsKey(TOKEN_ID)) {
      info.put(TOKEN_ID,tokenId);
    } else {
      tokenId = (String) info.get(TOKEN_ID);
    }
    result.setAdditional@R_393_4045@ion(info);
    result.setValue(encode(result,authentication));
    OAuth2RefreshToken refreshToken = result.getRefreshToken();
    if (refreshToken != null) {
      DefaultOAuth2Accesstoken encodedRefreshToken = new DefaultOAuth2Accesstoken(accesstoken);
      encodedRefreshToken.setValue(refreshToken.getValue());
      // Refresh tokens do not expire unless explicitly of the right type
      encodedRefreshToken.setExpiration(null);
      try {
        Map<String,Object> claims = jsonParser
            .parseMap(JwtHelper.decode(refreshToken.getValue()).getClaims());
        if (claims.containsKey(TOKEN_ID)) {
          encodedRefreshToken.setValue(claims.get(TOKEN_ID).toString());
        }
      } catch (IllegalArgumentException e) {
      }
      Map<String,Object> refreshTokenInfo = new LinkedHashMap<>(
          accesstoken.getAdditional@R_393_4045@ion());


      // <custom-code>
      refreshTokenInfo.remove("b");
      // </custom-code>


      refreshTokenInfo.put(TOKEN_ID,encodedRefreshToken.getValue());
      refreshTokenInfo.put(ACCESS_TOKEN_ID,tokenId);
      encodedRefreshToken.setAdditional@R_393_4045@ion(refreshTokenInfo);
      DefaultOAuth2RefreshToken token = new DefaultOAuth2RefreshToken(
          encode(encodedRefreshToken,authentication));
      if (refreshToken instanceof ExpiringOAuth2RefreshToken) {
        Date expiration = ((ExpiringOAuth2RefreshToken) refreshToken).getExpiration();
        encodedRefreshToken.setExpiration(expiration);
        token = new DefaultExpiringOAuth2RefreshToken(encode(encodedRefreshToken,authentication),expiration);
      }
      result.setRefreshToken(token);
    }
    return result;
  }

}

不同有效负载的上下文

我们有一个移动应用程序,需要将其访问权限和刷新令牌传递到Web视图。在Web视图中运行的应用程序没有后备服务器(由CDN提供的React Javascript应用程序)。我们的访问和刷新令牌包含从单独的单点登录系统发出的嵌套令牌,我们实际上是该单点登录系统的增强型代理。结果,我们发行的令牌相当大-我在自己的测试中生成了2000+个字符访问令牌。为了将令牌传递到Web视图,我们通过查询参数传递令牌。由于某些浏览器具有URL限制,我们希望SSO的访问令牌仅出现在我们的访问令牌中,而SSO的刷新令牌仅出现在我们的刷新令牌中,因为这将减轻URL膨胀-SSO的访问令牌已满- JWT,而其刷新令牌是简单的GUID。

我们知道,通过查询参数传递JWT并不是最佳实践,并且已经阅读了RFC。我们的任务期限很紧,这被认为是最快可行的解决方案。我们正在设计一种令牌交换微服务,以在将来解决此问题。

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)