改造与改造RxJava2刷新令牌并重试

时间:2018-05-01 13:18:33

标签: android kotlin rx-java2

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

现在我的应用程序充满了遍布各处的改装调用,我可能会在任何特定时刻获得401,所以每次刷新401时我怎么能这样做发出令牌,然后重试原始请求?

这是我的刷新签名:

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

我考虑过使用方法withAuth()创建一个基础知识库类,它接受任何Observable / Single / Flowable然后应用此逻辑但我找不到方法实施它。

看到了很多实现,但没有一个符合我的需求......任何人都可以把我推向正确的方向吗?

This is the closest我发现,平面图上似乎有一些错误

3 个答案:

答案 0 :(得分:0)

我刚遇到类似的要求,并提出了以下解决方案。这很简单,它仅尝试调用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响应,但是代码应该为您提供解决问题的总体方法。 / p>

答案 1 :(得分:0)

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

答案 2 :(得分:0)

您可以使用Interceptor拦截每个请求,并检查它是否返回401-未经授权的访问,并且iff然后刷新令牌并重播当前的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);
 }
}