如何为Retrofit请求头添加Access Token并通过Refresh Token刷新?
Retrofit请求头自动添加Access Token并实现Refresh Token刷新方案
我之前一直被Retrofit请求中Access Token的自动注入以及过期后用Refresh Token刷新的问题困扰,试了不少方法后,终于整理出一套对我来说最简单有效的实现方案,分享给有同样需求的开发者。
核心思路
通过OkHttp拦截器统一处理请求头的Token注入,同时在请求因Token过期失败时,自动调用刷新接口获取新的Access Token,并重试原请求。
具体实现
1. 定义Token管理类
先写一个单例类来全局统一管理Access Token和Refresh Token的存储与获取:
object TokenManager { private var accessToken: String? = null private var refreshToken: String? = null fun setTokens(access: String, refresh: String) { accessToken = access refreshToken = refresh } fun getAccessToken(): String? = accessToken fun getRefreshToken(): String? = refreshToken }
2. 实现Token注入拦截器
创建OkHttp拦截器,在每个请求头中自动添加Access Token:
class TokenInterceptor : Interceptor { override fun intercept(chain: Interceptor.Chain): Response { val originalRequest = chain.request() val token = TokenManager.getAccessToken() val authenticatedRequest = token?.let { originalRequest.newBuilder() .header("Authorization", "Bearer $it") .build() } ?: originalRequest return chain.proceed(authenticatedRequest) } }
3. 实现Token刷新与重试拦截器
这个拦截器负责检测请求是否因Token过期失败,若失败则触发Token刷新并重试原请求:
class RefreshTokenInterceptor(private val retrofit: Retrofit) : Interceptor { @Synchronized override fun intercept(chain: Interceptor.Chain): Response { val request = chain.request() val response = chain.proceed(request) // 假设后端返回401状态码表示Token过期,可根据实际情况调整 if (response.code == 401) { response.close() val newToken = refreshAccessToken() ?: return response // 用新的Access Token重新构建请求并重试 val newRequest = request.newBuilder() .header("Authorization", "Bearer $newToken") .build() return chain.proceed(newRequest) } return response } private fun refreshAccessToken(): String? { val refreshToken = TokenManager.getRefreshToken() ?: return null return try { val apiService = retrofit.create(AuthApi::class.java) val response = apiService.refreshToken(refreshToken).execute() if (response.isSuccessful) { val newTokens = response.body() ?: return null TokenManager.setTokens(newTokens.accessToken, newTokens.refreshToken) newTokens.accessToken } else { null } } catch (e: Exception) { null } } }
4. 配置Retrofit客户端
将两个拦截器添加到OkHttp客户端,注意拦截器的顺序:
// 先创建基础Retrofit实例(用于刷新Token的接口调用) val baseRetrofit = Retrofit.Builder() .baseUrl("https://your-api-domain.com/") .addConverterFactory(GsonConverterFactory.create()) .build() // 配置OkHttp客户端,添加拦截器 val okHttpClient = OkHttpClient.Builder() .addInterceptor(TokenInterceptor()) .addInterceptor(RefreshTokenInterceptor(baseRetrofit)) .build() // 最终的Retrofit实例 val retrofit = Retrofit.Builder() .baseUrl("https://your-api-domain.com/") .client(okHttpClient) .addConverterFactory(GsonConverterFactory.create()) .build()
注意事项
- 确保刷新Token的接口不需要携带Access Token,或有独立的认证逻辑
- 用
@Synchronized修饰拦截方法是为了避免并发请求时多次重复刷新Token,也可根据需求用其他线程安全方案替代 - 需根据后端实际返回的错误标识调整Token过期的判断逻辑,不一定是401状态码
这个方案逻辑清晰、代码量小,能覆盖大部分场景下的Token自动注入与刷新需求,对我来说是最省心的实现方式。
内容的提问来源于stack exchange,提问作者Farshad Molazeinali
相关产品推荐
相关产品推荐

