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

时间:2019-01-15 10:17:08

标签: android ios concurrency oauth-2.0 network-programming

我了解使用OAuth2的流程是:

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

要在iOS(带有AFNetworking)或Android(带有Volley)应用中实现它,我想网络管理员必须能够检测到返回的401错误,然后将请求发送到身份验证服务器。

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

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

最终结果是req2将失败,并且由于403错误,该应用将用户注销。

所以我的问题是

此实现是否朝着正确的方向发展?还是收到401后刷新不正确?我应该在用户启动应用程序时刷新令牌吗(以降低应用程序启动速度为代价)

如何解决并发问题?

1 个答案:

答案 0 :(得分: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在等待新的访问令牌。