赞
踩
服务端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过期的处理方案的分享就到这里,如果你还有更好的方案,欢迎留言分享
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。