如何在组件中暴露模块提供的命名属性?拦截器动态设置access_token
解决动态更新Retrofit拦截器中access_token的问题
嗨,这个场景我太熟悉了!核心就是要让你的授权拦截器能动态获取最新的access_token,而不是在初始化时就固定死配置。给你分享两个最实用的实现方案:
方案一:用可更新的Token持有者(推荐)
这个方法最简单直接,不需要重新创建Retrofit或OkHttpClient实例,拦截器每次请求时都会主动获取最新的token。
步骤1:创建Token持有者类
先写一个用来存储和更新token的类,注意线程安全(避免多线程下token更新不及时的问题):
class TokenHolder { // 用@Volatile保证多线程下的可见性 @Volatile var accessToken: String? = null }
或者用AtomicReference实现更严谨的线程安全:
class TokenHolder { private val tokenRef = AtomicReference<String?>() fun updateToken(newToken: String?) { tokenRef.set(newToken) } fun getCurrentToken(): String? { return tokenRef.get() } }
步骤2:在NetworkModule中注入TokenHolder和拦截器
让拦截器依赖这个TokenHolder,每次拦截请求时从holder中拿最新的token:
@Provides @Singleton fun provideTokenHolder(): TokenHolder = TokenHolder() @Provides @Singleton fun provideAuthInterceptor(tokenHolder: TokenHolder): Interceptor { return Interceptor { chain -> val requestBuilder = chain.request().newBuilder() // 只有当token存在时才添加请求头 tokenHolder.getCurrentToken()?.let { token -> requestBuilder.addHeader("Authorization", "Bearer $token") } chain.proceed(requestBuilder.build()) } } // 接着把这个拦截器添加到OkHttpClient中 @Provides @Singleton fun provideOkHttpClient(authInterceptor: Interceptor): OkHttpClient { return OkHttpClient.Builder() .addInterceptor(authInterceptor) // 其他配置(比如超时、日志拦截器等) .build() }
步骤3:获取到access_token后更新TokenHolder
当用户登录成功拿到access_token时,直接更新TokenHolder里的值就行:
// 比如登录接口回调中 tokenHolder.updateToken("your_new_access_token")
之后所有的请求都会自动带上最新的Authorization头了。
方案二:用复合拦截器动态替换授权逻辑
如果你的场景需要完全替换拦截器(而不是仅仅更新token),可以用一个复合拦截器来包装授权逻辑,动态添加或移除授权拦截器。
步骤1:创建复合授权拦截器
class CompositeAuthInterceptor : Interceptor { private val authInterceptor = AtomicReference<Interceptor?>(null) // 动态设置授权拦截器 fun setAuthInterceptor(interceptor: Interceptor?) { authInterceptor.set(interceptor) } override fun intercept(chain: Interceptor.Chain): Response { // 如果有授权拦截器就执行,否则直接放行请求 return authInterceptor.get()?.intercept(chain) ?: chain.proceed(chain.request()) } }
步骤2:在NetworkModule中配置复合拦截器
@Provides @Singleton fun provideCompositeAuthInterceptor(): CompositeAuthInterceptor = CompositeAuthInterceptor() @Provides @Singleton fun provideOkHttpClient(compositeAuthInterceptor: CompositeAuthInterceptor): OkHttpClient { return OkHttpClient.Builder() .addInterceptor(compositeAuthInterceptor) // 其他配置 .build() }
步骤3:拿到token后设置授权拦截器
// 登录成功后,创建带token的授权拦截器并设置进去 val authInterceptor = Interceptor { chain -> chain.proceed( chain.request().newBuilder() .addHeader("Authorization", "Bearer $accessToken") .build() ) } compositeAuthInterceptor.setAuthInterceptor(authInterceptor)
总结
方案一的代码更简洁,性能也更好(不需要额外的对象切换),是大多数场景的首选。方案二更灵活,适合需要动态替换整个拦截逻辑的情况。
内容的提问来源于stack exchange,提问作者vendettacore
相关产品推荐
相关产品推荐

