服务端API请求现在基本上都会设置token,用来保证接口识别安全和验证,一般来说token都会设置一个有效的时间,当时间过期之后我们需要重新获取一个新的token,从而保证接口的安全性。
那么,当token有效时间过期后我们应该怎样处理了,有两种方案,分别是手动处理和自动处理,选择哪种方案就看看应用适合哪种场景。
手动处理
手动处理意味着当token过期后需要客户手动点击重新获取一个新的token,常规做法是当token过期后,应用直接跳转至登录界面,重新走一遍登录的流程,获取新的token,更新本地缓存,从而保证后续接口的正常请求操作。
首先,怎么判断接口token失效,我的接口请求是采用Retrofit+Okhttp框架,需要在Retrofit请求中配置拦截,如图代码示例
retrofit = new Retrofit.Builder().client(new OkHttpClient.Builder()
.addInterceptor(new Interceptor() {
@Override
public Response intercept(Chain chain) throws IOException {
Request newRequest = chain.request().newBuilder()
.addHeader("Authorization", UserHelpers.getInstance().getAuthorization())
.build();
Response proceed = chain.proceed(newRequest);
/*token过期重新登录*/
if(isTokenExpired(proceed))
loginAgain();
else
isTokenExpire=false;
return proceed;
}
})
.addInterceptor(interceptor)
.retryOnConnectionFailure(true)
.readTimeout(TIMEOUT_READ, TimeUnit.SECONDS)
.connectTimeout(TIMEOUT_CONNECTION, TimeUnit.SECONDS)
.build()).baseUrl(RetrofitWrapper.Constant.BASE_URL).addConverterFactory(
GsonConverterFactory.create()).addCallAdapterFactory(RxJava2CallAdapterFactory.create()).build();
在新增的 addInterceptor中配置回调结果的拦截,如果出现token异常则走对应的流程进行重新登录。
isTokenExpired根据回调接口判断token是否过期
private boolean isTokenExpired(Response response) {
try {
ResponseBody responseBody = response.body();
BufferedSource source = responseBody.source();
source.request(Long.MAX_VALUE); // Buffer the entire body.
Buffer buffer = source.getBuffer();
Charset UTF8 = Charset.forName("UTF-8");
String string = buffer.clone().readString(UTF8);
ResponseEntity responseEntity = ResponseWrapper.getResponseEntity(string);
if(responseEntity.getCode()==MSG_CODE_TOKEN_FAIL)
return true;
} catch (IOException e) {
e.printStackTrace();
}
return false;
}
loginAgain()重新跳转登录界面
private void loginAgain()
{
Activity activity = ScreenManager.getScreenManager().currentActivity();
if (activity != null) {
activity.startActivity(new Intent(activity, LoginActivity.class)
.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK));
ScreenManager.getScreenManager().popAllActivity();
}
}
这里有很多种实现的方法,目的就是正常跳转登录界面即可
自动处理
自动处理的方案原理就是当token判断失效后,马上获取一个新的token保证接口能正常请求完成
retrofit = new Retrofit.Builder().client(new OkHttpClient.Builder()
.addInterceptor(new Interceptor() {
@Override
public Response intercept(Chain chain) throws IOException {
Request newRequest = chain.request().newBuilder()
.addHeader("Authorization", UserHelpers.getInstance().getAuthorization())
.build();
Response proceed = chain.proceed(newRequest);
// /*token过期重新登录*/
// if(isTokenExpired(proceed))
// loginAgain();
// else
// isTokenExpire=false;
if(isTokenExpired(proceed)) {
String newToken = getNewToken();
//使用新的Token,创建新的请求
Request newAgainRequest = chain.request().newBuilder()
.addHeader("Authorization", newToken)
.build();
return chain.proceed(newAgainRequest);
}
return proceed;
}
})
.addInterceptor(interceptor)
.retryOnConnectionFailure(true)
.readTimeout(TIMEOUT_READ, TimeUnit.SECONDS)
.connectTimeout(TIMEOUT_CONNECTION, TimeUnit.SECONDS)
.build()).baseUrl(RetrofitWrapper.Constant.BASE_URL).addConverterFactory(
GsonConverterFactory.create()).addCallAdapterFactory(RxJava2CallAdapterFactory.create()).build();
如图当token过期后,我们马上获取一个新的token从而继续完成整个接口请求。
getNewToken()获取一个新的token
private String getNewToken() throws IOException {
Retrofit retrofit= new Retrofit.Builder()
/*API的主机地址*/
.baseUrl("https://url")
.addConverterFactory(GsonConverterFactory.create())
.build();
retrofit2.Response<JsonObject> requestToken = retrofit.create(ApiProtocol.class).DriverLogin().execute();
/*生成新的token*/
String token=requestToken.body().get("Token").toString();
/*需要更新本地的token保存*/
return token;
}
并发处理
很多时候我们可能存在多个接口并发请求的情况,这个时候如果token失效,我们需要做一些特殊的处理,如果手动解决方案,我们参考下面的解决方案
在跳转的时候加一个token过期标识判断,当第一个接口已经判断token过期后,后续的的无需在处理
/token过期重新登录/
if(isTokenExpired(proceed))
loginAgain();
else
isTokenExpire=false;
private void loginAgain()
{
/*处理并发请求过期判断*/
if(isTokenExpire)
return;
else
isTokenExpire=true;
Activity activity = ScreenManager.getScreenManager().currentActivity();
if (activity != null) {
activity.startActivity(new Intent(activity, LoginActivity.class)
.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK));
ScreenManager.getScreenManager().popAllActivity();
}
}
如果是自动解决方案则在处理刷新的token的方法中需要采用同步的方式,这样第一个接口处理刷新完token后,后续的接口都可以正常请求接口。
@Synchronized
private String getNewToken() throws IOException {
Retrofit retrofit= new Retrofit.Builder()
/*API的主机地址*/
.baseUrl("https://url")
.addConverterFactory(GsonConverterFactory.create())
.build();
retrofit2.Response<JsonObject> requestToken = retrofit.create(ApiProtocol.class).DriverLogin().execute();
/*生成新的token*/
String token=requestToken.body().get("Token").toString();
/*需要更新本地的token保存*/
return token;
}
关于token过期的处理方案的分享就到这里,如果你还有更好的方案,欢迎留言分享