繁体   English   中英

如何删除 Dagger Hilt 依赖注入循环

[英]How to remove Dagger Hilt dependency Injection cycle

我有一个提供ApiService实例的网络模块 class。 有一个Authenticator class,它在过期时刷新访问令牌。 身份验证器需要ApiService实例来进行 API 调用。 这会导致循环依赖。 如何避免这种情况?

现在我在TokenExpiryAuthenticator class 中创建一个新的ApiService来进行 API 调用,以打破循环依赖。 如何正确地将ApiService注入TokenExpiryAuthenticator而不会导致循环依赖?

@InstallIn(SingletonComponent::class)
@Module
object NetworkModule {

@Provides
@Singleton
@Named("Other")
fun provideRetrofitWithoutInterceptor(@Named("Other") client: OkHttpClient, gson: Gson): Retrofit {
    return Retrofit.Builder()
        .baseUrl(BuildConfig.BASE_URL)
        .client(client)
        .addConverterFactory(GsonConverterFactory.create(gson))
        .build()
}

@Provides
@Singleton
fun provideRetrofit(client: OkHttpClient, gson: Gson): Retrofit {
    return Retrofit.Builder()
        .baseUrl(BuildConfig.BASE_URL)
        .client(client)
        .addConverterFactory(GsonConverterFactory.create(gson))
        .build()
}

@Provides
@Singleton
fun providesOkHttpClient(httpLoggingInterceptor: HttpLoggingInterceptor, supportInterceptor: SupportInterceptor, tokenExpiryAuthenticator: TokenExpiryAuthenticator): OkHttpClient {
    return OkHttpClient.Builder().writeTimeout(1, TimeUnit.MINUTES)
        .readTimeout(1, TimeUnit.MINUTES)
        .callTimeout(1, TimeUnit.MINUTES)
        .addInterceptor(httpLoggingInterceptor)
        .addInterceptor(supportInterceptor)
        .authenticator(tokenExpiryAuthenticator)
        .build()
}

@Named("Other")
@Provides
@Singleton
fun providesOkHttpClientWithoutInterceptor(httpLoggingInterceptor: HttpLoggingInterceptor): OkHttpClient {
    return OkHttpClient.Builder().writeTimeout(1, TimeUnit.MINUTES)
        .readTimeout(1, TimeUnit.MINUTES)
        .callTimeout(1, TimeUnit.MINUTES)
        .addInterceptor(httpLoggingInterceptor)
        .build()
}

@Provides
@Singleton
fun providesHttpLoggingInterceptor(): HttpLoggingInterceptor {
    return if (BuildConfig.DEBUG)
        HttpLoggingInterceptor().apply {
            level = HttpLoggingInterceptor.Level.BODY
        }
    else
        HttpLoggingInterceptor().apply {
            level = HttpLoggingInterceptor.Level.NONE
        }
}

@Provides
@Singleton
fun providesGson(): Gson {
    return GsonBuilder().create()
}

@Provides
@Singleton
fun providesRestApiService(retrofit: Retrofit): ApiService {
    return retrofit.create(ApiService::class.java)
}

@Provides
@Singleton
@Named("Other")
fun providesRestApiServiceWithoutInterceptor(@Named("Other") retrofit: Retrofit): ApiService{
    return retrofit.create(ApiService::class.java)
}

}

您可以拆分 ApiService 并创建一个新的 AuthenticationApi,它仅包含用于验证或刷新访问令牌的端点。 此 AuthenticationApi 是使用没有 Authenticator 的 OkHttp 实例创建的。

这样你的身份验证器只需要参考这个苗条的 Retrofit api。这也保证你不会得到 HTTP 401 身份验证循环,以防在使用身份验证端点时出现错误的凭据。

最简单的解决方案是延迟注入依赖项。

class TokenExpiryAuthenticator @Inject constructor(
  private val api: Lazy<ApiService>,
  private val persistence: TokenPersistenceRepository
) : Authenticator {

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

    // If HTTP 401 error was raised while trying to refresh token it means
    // the token is invalid (or expired). Sign out user and do not
    // proceed with further requests.
    if (response.request.url.encodedPath == REFRESH_TOKEN_PATH) {

      // Perform any cleanup needed.
      
      // Return null so no further requests will be performed.
      return null
    }

    // Request failed for old token. It's about time to refresh it.
    if (response.request.header(AUTH_HEADER) != null) {
      
      // Refresh access token using your lazily injected service.
      persistence
        .retrieveRefreshToken()
        .flatMap(api.get()::refreshToken)
        .flatMapCompletable {
          Completable.concatArray(
            persistence.saveAccessToken(it.accessToken),
            persistence.saveRefreshToken(it.refreshToken),
          )
        }
        .blockingAwait()
        // You can use blocking await as the [authenticate] method is
        // run on I/O thread anyway.
    }

    // Load recently refreshed access token.
    val token = (...)
    
    // Format authorization header value.
    val header = (...)
    
    // Modify and proceed with a request with refreshed access token.
    return response.request.newBuilder()
      .removeHeader(AUTH_HEADER)
      .addHeader(AUTH_HEADER, header)
      .build()
  }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM