When to exchange access token with refresh token
我理解使用 OAuth2 的流程是:
在短期访问令牌过期后(服务器返回 401),客户端必须使用刷新令牌请求新的。
要在 iOS(使用 AFNetworking)或 Android(使用 Volley)应用程序中实现它,我想网络管理器必须能够检测返回的 401 错误,然后向身份验证服务器发送请求。
问题在于网络的并发使用。考虑访问已过期的场景,应用程序发送 2 个请求:req1 和 100 毫秒后,req2。绘制在时间轴上,如下所示:
1 2
|
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 也可以,问题是如何兑换代币
-
您需要使用 refretoken 生成新令牌,并且必须更新原始请求标头,并且再次需要使用新的 accesstoken 请求服务器。在拦截器中
-
我理解,但这不是我的问题。我遇到了并发问题。
-
@Siyu您是否已经有一些适用于顺序请求但可能在并行请求上失败的令牌管理器实现?
-
@JánHala??是的。如果我一个一个发送请求,它会起作用
由于您有一个现有的令牌管理器,我会在其中添加一些额外的逻辑(在 Java 中):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
|
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 中的 Promise – 异步结果)。如果需要刷新访问令牌,请先检查 /token 端点请求是否已在运行。如果是,则返回它的 CompletableFuture.
这样,您将始终拥有一个有效的访问令牌或单个 CompletableFuture 等待新的访问令牌。
- 所以这个想法是在发送任何请求之前检查令牌?
-
是的,我认为在发送之前检查它是件好事——它更快,并且您可以避免太多被禁止的请求访问服务器。但是,如果您从资源服务器获得 HTTP 403,您应该使用刷新的访问令牌重试。
-
好的,但是如果我确实收到了 403,我该如何避免遇到我帖子中描述的情况?
-
对不起,我的意思是 HTTP 401 – 然后你会得到一个刷新的访问令牌。您不应收到 HTTP 403 – req1 将要求刷新令牌并等待它返回,而 req2 将检测到等待刷新的令牌。然后他们都将使用相同的有效访问令牌。
-
抱歉,我对此有点固执,但是我如何检测到 req1 正在请求新令牌并阻止 req2?
-
Req1 将要求 TokenManager 获取新的访问令牌。 TokenManager 将返回一个 CompletableFuture。当 req2 请求新的访问令牌时,TokenManager 将返回相同的 CompletableFuture,因为请求尚未完成。所以 req2 不会检测到访问令牌已经被刷新,但它会被阻塞(它的线程),直到获得刷新的令牌。
原创文章,作者:ItWorker,如若转载,请注明出处:https://blog.ytso.com/268608.html