何时用刷新令牌交换访问令牌

Posted

技术标签:

【中文标题】何时用刷新令牌交换访问令牌【英文标题】:When to exchange access token with refresh token 【发布时间】:2019-01-15 10:17:07 【问题描述】:

我了解使用 OAuth2 的流程是:

在短期访问令牌过期(服务器返回 401)后,客户端必须使用刷新令牌请求一个新令牌。

要在 ios(使用 AFNetworking)或 android(使用 Volley)应用程序中实现它,我想网络管理器必须能够检测返回的 401 错误,然后向身份验证服务器发送请求。

问题在于网络的并发使用。考虑访问已过期的场景,应用程序发送 2 个请求:req1 和 100 毫秒后,req2。绘制在时间轴上,如下所示:

req1 --> 401 --> (refresh req) --> OK, new access and fresh tokens --> retry req1
  req2 --> 401 --> (refresh req) --> 403, wrong refresh token

最终结果是req2会失败,应用会因为403错误退出用户。

所以我的问题是

这个实现是否朝着正确的方向发展?还是收到401后刷新不对?我是否应该在用户启动应用程序时刷新令牌(以减慢应用程序启动为代价)

如何解决并发问题?

【问题讨论】:

你在android中使用哪个库进行api调用?? @ChandrakantDvivedi 我正在使用 Volley 我用的是okHttp,这里提供了拦截器,可以在请求和响应之间进行拦截。 Volley 也可以,问题是如何兑换代币 @Siyu 你是否已经有一些令牌管理器实现,适用于顺序请求但可能会在并行请求上失败? 【参考方案1】:

由于您有一个现有的令牌管理器,我会在其中添加一些额外的逻辑(在 Java 中):

class TokenManager 

  private String accessToken;
  private CompletableFuture<String> accessTokenRefreshComletableFuture;

  public CompletableFuture<String> getAccessToken() 
    if (this.accessToken is expired) 
       // If refreshed accessToken is being requested
       CompletableFuture<String> runningRequestFuture = this.accessTokenRefreshComletableFuture;
       if (runningRequestFuture == null) 
          // For thread safety, this assignment should be synchronized (or made atomic)
          // with the previous reading
          this.accessTokenRefreshComletableFuture = new CompletableFuture<>();
          // Request a fresh access token.
          // When you get a new access token, set the this.accessTokenRefreshComletableFuture 
          // complete and remove its reference from the manager class.
       
       return runningRequestFuture;
    
    // Synchronous result
    return CompletableFuture.completedFuture(this.accessToken);
  

管理器不返回访问令牌,而是返回 CompletableFuture(javascript 中的承诺 - 异步结果)。如果需要刷新访问令牌,首先检查/token端点请求是否已经在运行。如果是,则返回CompletableFuture

这样,您将始终拥有一个有效的访问令牌或一个 CompletableFuture 等待新的访问令牌。

【讨论】:

所以想法是在发送任何请求之前检查令牌? 是的,我认为在发送之前检查它是件好事——它更快,并且可以避免太多被禁止的请求访问服务器。但如果您从资源服务器获得 HTTP 403,您应该使用刷新的访问令牌重试。 好的,但是如果我得到了 403,我该如何避免遇到我帖子中描述的情况? 对不起,我的意思是 HTTP 401 - 然后你会得到一个刷新的访问令牌。你不应该得到 HTTP 403 - req1 将要求刷新令牌并等待它返回,req2 将检测到等待刷新的令牌。然后他们都将使用相同的有效访问令牌。 对不起,我对此有点固执,但是如何检测到 req1 正在请求新令牌并阻止 req2?

以上是关于何时用刷新令牌交换访问令牌的主要内容,如果未能解决你的问题,请参考以下文章

何时将刷新令牌传递给 API

无法在跨客户端谷歌 oauth2.0 中交换访问令牌和刷新令牌的授权码

从passportjs中的刷新令牌获取oauth访问令牌

google oauth2 刷新令牌何时过期?

如何识别OAuth令牌是否已过期?

如何使用刷新令牌刷新访问令牌?