OkHttp 身份验证器在获取新的 tioken 请求后循环

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

我正在制作一个基本应用程序来访问使用短期令牌作为 API 的 Twitch 服务器。因此,我使用 Retrofit 和 Hilt 创建了一个

okhttp3.Authenticator
类,用于处理添加令牌以进行身份验证,这与我在教程中甚至在 SO 中看到的其他几个非常相似。通常,当出现 401 秒时,会获取一个新令牌并将其添加到 newRequest 标头中的响应中,但由于某种原因,它在该阶段保持循环并因
too many requests
错误而中断。

这是一个与这个问题非常相似的问题,但即使在实施了公认的解决方案之后,它仍然会循环。

知道可能是什么问题吗?

我的身份验证器:

class AuthAuthenticator @Inject constructor(
    private val sessionManager: SessionManager,
    private val authApi: AuthApi
) : Authenticator {


    override fun authenticate(route: Route?, response: Response): Request? {
        return runBlocking {

        // call login api again for getting accessToken
        val apiResponse = getNewToken()

        if (apiResponse.isSuccessful) {
            val accessToken = apiResponse.body()?.token ?: return@runBlocking null                
            val expireTime = apiResponse.body()?.expireTime ?: return@runBlocking null
            accessToken.let {                    
                sessionManager.saveToken(accessToken, expireTime)
            }                
            response
                    .request                    
                    .newBuilder()
                    .header("Authorization", "Bearer $accessToken")
                    .build()
            } else {
                null            
            }
        }    
    }

    private suspend fun getNewToken(): retrofit2.Response<TokenResponse> {
        return authApi.getAuthToken(
            clientId = ExternalInfoHelper.valuesMap()[ApiValues.clientIdKey] ?: "",
            clientSecret = ExternalInfoHelper.valuesMap()[ApiValues.clientSecretKey] ?: "",
            grantType = ExternalInfoHelper.valuesMap()[ApiValues.grantTypeKey] ?: ""        )
    }
}


我像这样初始化 okhttp 客户端,使用一些 DI 来处理不同的改造客户端,因为 URL 不同:

private fun createOkHttpClient(
    authInterceptor: AuthInterceptor?,
    authAuthenticator: AuthAuthenticator?
): OkHttpClient {
    val loggerInterceptor = HttpLoggingInterceptor()
    loggerInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY)
    val okhttp = OkHttpClient.Builder()
        .addInterceptor(loggerInterceptor)

    authAuthenticator?.let {        
        okhttp.authenticator(it)
    }    
    authInterceptor?.let {        
        okhttp.addInterceptor(it)
    }    return okhttp.build()
}


这是我的拦截器,用于添加存储的令牌:

class AuthInterceptor @Inject constructor(private val sessionManager: SessionManager) :
    Interceptor {

    override fun intercept(chain: Interceptor.Chain): Response {
        val token = runBlocking {            
            sessionManager.getToken().first()
        }        
        val request = chain.request().newBuilder()
        request.addHeader(ApiValues.authHeaderKey, ApiValues.authHeaderValue.plus(token))
        return chain.proceed(request.build())
    }
}


我尝试用几种不同的方式重写代码,返回 null 并且不会改变循环。 使用从 Postman 获得的硬编码值返回请求会在日志中出现

too many requests
错误,而实际上没有执行任何请求

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

首先,验证 AuthAuthenticator 类是否已正确注入并由 Hilt 提供。确保依赖项 SessionManager 和 AuthApi 已正确注入并可用。

接下来,让我们仔细看看您的

中的authenticate功能
AuthAuthenticator class:

override fun authenticate(route: Route?, response: Response): Request? {
    return runBlocking {
        // call login api again for getting accessToken
        val apiResponse = getNewToken()

        if (apiResponse.isSuccessful) {
            // ... code to save and set the new access token ...

            response
                .request                    
                .newBuilder()
                .header("Authorization", "Bearer $accessToken")
                .build()
        } else {
            null            
        }
    }    
}

根据您提供的代码片段,您似乎缺少更新的请求对象的分配。 response.request.newBuilder() 方法创建一个新的请求构建器,但您需要将其分配回response.request,以便使用新的访问令牌标头更新请求。修改代码如下:

override fun authenticate(route: Route?, response: Response): Request? {
    return runBlocking {
        // call login api again for getting accessToken
        val apiResponse = getNewToken()

        if (apiResponse.isSuccessful) {
            // ... code to save and set the new access token ...

            response
                .request
                .newBuilder()
                .header("Authorization", "Bearer $accessToken")
                .build()
        } else {
            null            
        }
    }    
}
© www.soinside.com 2019 - 2024. All rights reserved.