【问题标题】:Retrofit & RxJava2 refresh token and retry改造 & RxJava2 刷新令牌并重试
【发布时间】:2018-05-01 13:18:33
【问题描述】:

我有一个登录端点,我通过它接收一个 authToken 和一个 refreshToken。第一个将在一小时后到期,所以我应该使用第二个来刷新它并继续应用程序流程。

现在我的应用程序到处都是改造调用,我可能会在任何给定时刻获得401,所以我怎样才能做到每次我收到401 时都会发出刷新令牌,然后重试原来的请求?

这是我的刷新签名:

 @POST("/auth/actions/refresh")
    fun refreshToken(@Body tokenRefresh: TokenRefresh): Single<LoginResponse>

我曾考虑使用 withAuth() 方法创建一个基础存储库类,该方法采用任何 Observable/Single/Flowable,然后应用此逻辑,但我找不到实现它的方法。

看到了一堆实现,但没有一个符合我的需求……谁能把我推向正确的方向?

This is the closest我找到了,但是平面映射似乎有一些错误

【问题讨论】:

    标签: android kotlin rx-java2


    【解决方案1】:

    我刚刚遇到了类似的要求并提出了以下解决方案。这非常简单,它只是尝试调用 REST 端点,如果调用失败并出现 HTTP 401,它会重新验证并再次重复调用。否则它只会发出原始错误。

    fun <T> Single<T>.withAuth() = retryWhen { errors ->
        var firstAttempt = true
        errors.flatMapSingle { error ->
            if (firstAttempt && error is HttpException && error.code() == 401) {
                firstAttempt = false
                reauthenticate()
            } else {
                Single.error(it)
            }
        }
    }
    

    其中重新认证功能具有以下签名:

    fun reauthenticate(): Single<AnyAuthResponse>
    

    请注意,具体的异常类型可能取决于您实际使用的 HTTP 实现,因此您可能需要更新条件以检测 HTTP 401 响应,但代码应为您提供如何解决问题的总体情况。

    【讨论】:

      【解决方案2】:

      我认为您可以在不修改所有调用的情况下执行此操作。将Authenticator 添加到您的改造中 Refreshing OAuth token using Retrofit without modifying all calls

      【讨论】:

        【解决方案3】:

        您可以使用 Interceptor 拦截每个请求并检查它是否返回 401 - 未经授权的访问,然后刷新令牌并重播当前的 API 请求。

        public final class SessionInterceptor implements Interceptor {
          // gets intercept
          @Override public Response intercept(@NonNull final Chain chain) throws IOException {
        
           final Request request = chain.request();
           final Response response = chain.proceed(request);
           final ResponseBody responseBody = response.body();
        
           if (response.code() == 401) {
              synchronized (this) {
              // Refresh your token
              // Update your authToken + Refreshed token
              final retrofit2.Response response = refreshToken();
              }
           }
        
           // Replay the original request
           // Perform request, here original request will be executed
           final Request original = chain.request();
           final Request.Builder builder = original.newBuilder();
        
           // Set your new refreshed token
           if (accessToken.isSet()) {
             builder.header(AUTHORIZATION, String.format(BEARER, 
             accessToken.get()));
            }
        
            final Request request = builder.method(original.method(), original.body()).build();
        
            return chain.proceed(request);
         }
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2019-09-05
          • 1970-01-01
          • 2022-08-06
          • 2022-08-06
          • 1970-01-01
          • 2017-04-14
          • 2020-11-22
          相关资源
          最近更新 更多