共计 1559 个字符,预计需要花费 4 分钟才能阅读完成。
背景与痛点
在移动应用开发中,Token 是身份验证的核心机制。但随着安全要求的提高,Token 的有效期越来越短,动态更新 Token 成为必须解决的问题。常见的痛点包括:

- Token 失效:用户操作过程中 Token 过期,导致后续请求失败
- 并发竞争:多个请求同时触发 Token 刷新,造成重复刷新或资源浪费
- 用户体验差:Token 失效后需要重新登录,打断用户操作流程
技术选型对比
目前主流的 Token 更新方案主要有三种:
- 全局管理方案
- 优点:实现简单,逻辑集中
-
缺点:难以处理并发请求,容易产生竞态条件
-
RxJava 方案
- 优点:响应式编程,处理异步流程优雅
-
缺点:学习成本高,对项目架构有要求
-
OkHttp 拦截器方案
- 优点:与网络层解耦,灵活可控
- 缺点:需要处理线程安全问题
经过对比,OkHttp 拦截器方案在灵活性和可维护性上更具优势。
核心实现细节
1. Token 自动刷新机制
核心思路是当请求返回 401 时自动刷新 Token,然后重试原请求。实现要点:
- 使用 OkHttp 的
Interceptor接口 - 通过同步锁防止并发刷新
- 添加 Token 刷新标记避免循环刷新
2. 请求重试逻辑
刷新 Token 成功后需要:
- 更新请求头中的 Token
- 重新构建请求
- 继续执行请求链
3. 并发控制
使用 synchronized 关键字确保同一时间只有一个线程能执行 Token 刷新操作,其他请求等待刷新完成。
代码示例
class TokenInterceptor(private val tokenManager: TokenManager) : Interceptor {@Throws(IOException::class)
override fun intercept(chain: Interceptor.Chain): Response {val originalRequest = chain.request()
val response = chain.proceed(originalRequest)
// 检查 Token 是否过期
if (response.code == HttpURLConnection.HTTP_UNAUTHORIZED) {synchronized(this) {
// 二次检查,防止重复刷新
if (tokenManager.isTokenExpired()) {
// 刷新 Token
val newToken = tokenManager.refreshToken()
// 使用新 Token 重试请求
val newRequest = originalRequest.newBuilder()
.header("Authorization", "Bearer $newToken")
.build()
return chain.proceed(newRequest)
}
}
}
return response
}
}
性能与安全考量
性能优化
- Token 预刷新:在 Token 接近过期时主动刷新,避免请求失败
- 缓存控制:合理设置 Token 缓存时间,减少网络请求
- 线程池优化:使用专用线程执行 Token 刷新
安全加固
- Token 存储:使用 Android Keystore 加密存储
- HTTPS 传输:确保 Token 传输过程加密
- 刷新频率限制:防止暴力刷新攻击
生产环境避坑指南
- 网络异常处理
- 增加刷新 Token 失败的重试机制
-
设置合理的超时时间
-
Token 存储安全
- 避免明文存储
-
使用 Android 安全存储方案
-
多设备登录处理
- 考虑设备唯一性
- 实现单点登录逻辑
总结与思考
Token 动态更新是移动应用安全架构的重要环节。本文介绍的方案虽然解决了核心问题,但在实际项目中还需要根据业务特点进行调整。例如:
- 对于高频请求应用,可能需要更积极的预刷新策略
- 对于金融类应用,可能需要更严格的安全措施
建议读者在理解原理的基础上,根据项目实际情况灵活调整实现方案。最好的学习方式是动手实践,尝试在自己的项目中实现这套机制,并观察实际效果。
正文完
