我了解使用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后刷新不正确?我应该在用户启动应用程序时刷新令牌吗(以降低应用程序启动速度为代价)
如何解决并发问题?
答案 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
在等待新的访问令牌。