我理解使用 OAuth2 的流程是:
在短期访问 token 过期后(服务器返回 401),客户端必须使用刷新 token 请求一个新的访问 token 。
要在 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后刷新不对?我是否应该在用户启动应用程序时刷新 token (以减慢应用程序启动速度为代价)
如何解决并发问题?
最佳答案
由于您有一个现有的 token 管理器,我会向其中添加一些额外的逻辑(用 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);
}
}
管理器不会返回访问 token ,而是返回 CompletableFuture (JavaScript 中的 Promise - 异步结果)。如果需要刷新访问 token ,请首先检查 /token
端点请求是否已在运行。如果是,则返回它的 CompletableFuture
。
这样,您将始终拥有一个有效的访问 token 或一个等待新访问 token 的 CompletableFuture
。
关于android - 何时用刷新 token 交换访问 token ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54196823/