背景
Token是当前用于客户端到服务端做身份验证的一种较为常见的机制. 客户端先通过用户名、密码登陆服务器,获取token,后续每次请求都带上token.当token在有效期内,服务器都校验通过,失效后,则返回鉴权失败,客户端需要重新登陆获取token. 如果过一段时间就需要用户登陆一次,这显然非常不友好.那怎么办呢?
解决方案
- 方案一、token设置为永远有效.
这显然是下下招,一旦token被人截获,就被人玩死了. - 方案二、app启动就检查token是否将要失效,如果是,则自动登陆刷新token,app运行中,也定时检查并刷新token.
- 方案三、每次请求前,都判断token是否将要失效,如果是,则自动登陆刷新token,然后再发出原请求.
- 方案四、Token失效拦截. 对所有请求(除登陆请求)进行拦截,如果token失效,则自动登陆刷新token,然后再发出原请求. 本文仅介绍此方案的具体实现方式.
Token失效拦截实现方法
- 为okhttp设置拦截器
其中HttpHeaderInterceptor是为所有请求添加token字段的拦截器;TokenInterceptor是检测token是否失效并重新登陆的拦截器.
OkHttpClient.Builder()
.apply {
addInterceptor(HttpHeaderInterceptor())
addInterceptor(TokenInterceptor())
}.build()
- token拦截器中,需对返回信息做判断,看是否失效.如果失效,则自动登陆,然后重新执行原请求.注意:自动登陆时,不能再采用coroutines异步执行,必须要用同步方式,才能登陆后执行原请求并返回执行结果给调用者.
class TokenInterceptor : Interceptor() {
override fun interceptMe(chain: Interceptor.Chain): Response {
val request = chain.request()
var response = chain.proceed(request)
if (isTokenExpired(response)) {
LoginManager.login(
onSuccess = {
val newRequest = replaceTokenInHeader(request, it.token)
response?.close()
response = chain.proceed(newRequest)
}
)
}
return response
}
/**
* 判断token是否失效。
* TODO: 下面函数isTokenExpired只是测试样例,固定返回true;应根据实际项目修改。
*/
private fun isTokenExpired(response: Response) = true//(response.code() == TOKEN_EXPIRED)
}
Demo源代码
https://gitee.com/cxyzy1/coroutineRetrofitDemo.git
安卓开发技术分享: https://www.jianshu.com/p/442339952f26
点击关注专辑,查看最新技术分享
更多技术总结好文,请关注:「程序园中猿」
网友评论