在 Android Retrofit 中并行调用多个 API 时刷新令牌的身份验证器

问题描述 投票:0回答:1

我想在访问令牌过期时刷新它。我已经实现了 Authenticator,如下所示:

@Singleton
class TokenAuthenticator(
    val authService: Lazy<AuthService>,
    private val sharedPreferences: SharedPreferences
) : Authenticator {


override fun authenticate(route: Route?, response: Response): Request? {
    return authRequestWithNewToken(response.request)
}

private fun authRequestWithNewToken(
    request: Request
): Request? {
    getFreshAccessToken()?.let { freshToken ->
        return getNewRequest(request, freshToken)
    }
    return null
}

private fun getFreshAccessToken(): String? {
    val refreshResponse = authService.get().refreshTokenTemp().execute()
    if (refreshResponse.isSuccessful) {
        val updatedAccessToken =
            refreshResponse.body()?.data?.accessToken ?: return null
        val updatedRefreshToken =
            refreshResponse.body()?.data?.refreshToken ?: return null
        updateToken(updatedAccessToken, updatedRefreshToken)
        Timber.tag("TOKEN")
            .d("Auth Updated token\n AccessToken: $updatedAccessToken \n RefreshToken: $updatedRefreshToken")
        return updatedAccessToken
    } else {
        return null
    }
}

private fun getNewRequest(request: Request, accessToken: String): Request {
    return request.newBuilder()
        .header(
            AppConstants.PARAMS.AUTH,
            AppConstants.PARAMS.BEARER + accessToken
        )
        .header("Accept", "application/json")
        .header("User-Agent", AppConstants.PARAMS.USER_AGENT)
        .build()
}

private fun updateToken(accessToken: String, refreshToken: String) {
    with(sharedPreferences.edit()) {
        putString(AppConstants.SHAREDPREFERENCE.ACCESS_TOKEN, accessToken)
        putString(AppConstants.SHAREDPREFERENCE.REFRESH_TOKEN, refreshToken).apply()
    }
    AppVariables.SessionData.accessToken = accessToken
    AppVariables.SessionData.refreshToken = refreshToken
    Timber.tag("TOKEN").d("Token Refreshed")
}
}

即使使用此功能后,由于发生并行 API 调用,我的应用程序仍然超时,并且用户被带到登录屏幕。

即使花了很多时间我也无法弄清楚出了什么问题。

我看到人们在尝试

@synchronised
,我尝试实施但没有成功。

最后我看到了this,他添加了这样的调度程序:

    @Singleton
    @Provides
    fun provideOkhttpClient(tokenAuthenticator: TokenAuthenticator): OkHttpClient {
     //***********like this**********************//
        val dispatcher = Dispatcher()
        dispatcher.maxRequests = 1
     //******************************************//
        return OkHttpClient.Builder()
            .dispatcher(dispatcher)
            .connectTimeout(180, TimeUnit.SECONDS)
            .readTimeout(180, TimeUnit.SECONDS)
            .writeTimeout(180, TimeUnit.SECONDS)
            .authenticator(tokenAuthenticator)
            .addInterceptor(TokenInterceptor())
            .build()
    }

这似乎解决了我的问题。但是,我不知道这意味着什么。是否建议在生产中使用?

我可以在文档中看到以下内容:

同时执行的最大请求数。上面这个 请求在内存中排队,等待正在运行的调用完成。 如果在调用此函数时有超过 maxRequests 的请求正在运行, 这些请求将继续进行。

我是否错过了一些可能会在以后咬我屁股的东西?

其他参考:link1 链接2

android retrofit okhttp refresh-token android-authenticator
1个回答
0
投票

您可以尝试此刷新令牌。

public class TokenManager {
    private String accessToken;
    private String refreshToken;
    private long tokenExpirationTime;

    // Other methods for setting, getting, and checking token details
}

public class TokenRefreshInterceptor implements Interceptor {
    @Override
    public Response intercept(Chain chain) throws IOException {
        Request originalRequest = chain.request();
        String accessToken = TokenManager.getInstance().getAccessToken();

        if (accessToken != null && !accessToken.isEmpty()) {
            // Add the access token to the request headers
            Request modifiedRequest = originalRequest.newBuilder()
                .header("Authorization", "Bearer " + accessToken)
                .build();
            return chain.proceed(modifiedRequest);
        }

        return chain.proceed(originalRequest);
    }
}

public class ApiService {
    // Retrofit API interfaces
}

public class ApiClient {
    private static Retrofit retrofit;

    public static Retrofit getClient() {
        if (retrofit == null) {
            OkHttpClient client = new OkHttpClient.Builder()
                .addInterceptor(new TokenRefreshInterceptor())
                .build();

            retrofit = new Retrofit.Builder()
                .baseUrl(BASE_URL)
                .client(client)
                .addConverterFactory(GsonConverterFactory.create())
                .build();
        }
        return retrofit;
    }
}

public class ApiCaller {
    public void makeApiCall() {
        ApiService apiService = ApiClient.getClient().create(ApiService.class);
        Call<ApiResponse> call = apiService.getSomeData();

        call.enqueue(new Callback<ApiResponse>() {
            @Override
            public void onResponse(Call<ApiResponse> call, Response<ApiResponse> response) {
                // Handle API response
            }

            @Override
            public void onFailure(Call<ApiResponse> call, Throwable t) {
                // Handle API failure
            }
        });
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.