OkHttp全局刷新token
来源:互联网 发布:大数据架构师做什么 编辑:程序博客网 时间:2024/06/11 02:52
OkHttp全局刷新token
前言:公司项目采用token验证,要求token失效后,能够自动刷新,并且如果有其他网络请求,能够用这个刷新后的token继续请求数据。
知识介绍:token分为access_token和refresh_token,access_token有效期为2个小时,refresh_token有效期为15天。access_token失效后,需要用refresh_token进行刷新。关于token机制可以看文章基于 Token 的身份验证。
解决方法:
1.通过拦截器,获取返回的数据
2.判断token是否过期
3.如果token过期则刷新token
4.使用最新的token,重新请求网络数据
5.关于重复请求token的问题
1、新建token拦截器,获取返回的数据
public class TokenInterceptor implements Interceptor { @Override public Response intercept(Chain chain) throws IOException { Response response = chain.proceed(requestBuilder.build()); if (isTokenExpired(response)) {//根据和服务端的约定判断token过期 String newToken = getNewToken(); if (!TextUtils.isEmpty(newToken)){ //使用新的Token,创建新的请求 Request newRequest = chain.request() .newBuilder() .removeHeader(AppConstant.AUTH_HEADER) .addHeader(AppConstant.AUTH_HEADER, "bearer "+newToken) .addHeader("Accept","application/json;version=1.2") .build(); //重新请求 return chain.proceed(newRequest); } else { //退出app到登录页面,重新登录 } } }
2、根据与后台商定的token过期码,判断是否token过期
private boolean isTokenExpired(Response response) { if(response.code() == 401) { ResponseBody body = response.body(); if (body != null){ try { MediaType mediaType = body.contentType(); if (mediaType != null) { if(isText(mediaType)) { String resp = body.string(); PostOkModel model = new Gson().fromJson(resp, PostOkModel.class); //4061是与后台商量的token失效后的错误码,具体应根据自己的项目决定 if(model.getCode() == 4601) { return true; } } } } catch (IOException e) { e.printStackTrace(); } } } return false; } private boolean isText(MediaType mediaType) { if (mediaType.type() != null && mediaType.type().equals("text")) { return true; } if (mediaType.subtype() != null) { if (mediaType.subtype().equals("json") || mediaType.subtype().equals("xml") || mediaType.subtype().equals("html") || mediaType.subtype().equals("webviewhtml") ) return true; } return false; }
3、token过期则进行刷新token
private static String getNewToken() throws IOException{ String refreshToken = SPDtadUtils.getString(UserApplication.getInstance(), "refreshToken");//之前存储在本地的refreshToken TokenRefreshPostModel model = new TokenRefreshPostModel(); model.refresh_token = refreshToken; model.client_id = BuildConfig.CLIENT_ID;//项目中的身份id,根据自己实际情况定 RequestBody body = RequestBody.create(AppConstant.MEDIA_TYPE_JSON, new Gson().toJson(model)); Request request = new Request.Builder().url(AppConstant.TOKEN_REFRESH).post(body).build(); Response newResponse = new OkHttpClient().newCall(request).execute(); Log.e("TAG", "刷新token"); if(newResponse.code() != 200) { return null; } ResponseBody responseBody = newResponse.body(); //以下代码为将token存储到本地 TokenInfoModel tokenInfoModel = new Gson().fromJson(responseBody.string(), TokenInfoModel.class); UserUtils.saveToken(UserApplication.getInstance(), tokenInfoModel); SPDtadUtils.putString(UserApplication.getInstance(), "new_token", tokenInfoModel.getAccess_token()); Log.e("TAG", "存储token"); //返回刷新后的token return tokenInfoModel.getAccess_token(); }
4、使用最新的token,重新进行网络请求
//使用新的Token,创建新的请求 Request newRequest = chain.request() .newBuilder() .removeHeader(AppConstant.AUTH_HEADER) .addHeader(AppConstant.AUTH_HEADER, "bearer "+newToken) .addHeader("Accept","application/json;version=1.2") .build(); //重新请求 return chain.proceed(newRequest);
5、关于重复请求token的问题
每一个网络请求都有一个自己的拦截器,那如何实现当一个网络请求正在刷新token的时候,其他网路请求需要等待;然后等token刷新后,其他的网路请求再使用这个刷新后的token呢。这时候就要用到java中的同步锁。关于同步锁的具体内容,请查看相关的知识。
加上同步锁以后的最终代码就是一下:
public class TokenInterceptor implements Interceptor { @Override public Response intercept(Chain chain) throws IOException { String tokenHeader = chain.request().header(ApiConstants.AUTH_HEADER_VALUE); GlobalDoctorData user = UserApplication.getInstance().getDoctorData(); Request.Builder requestBuilder = chain .request() .newBuilder(); if(TextUtils.isEmpty(tokenHeader) && user !=null && !TextUtils.isEmpty(user.getToken())) { requestBuilder .removeHeader(AppConstant.AUTH_HEADER) .addHeader(AppConstant.AUTH_HEADER, user.getToken()) .addHeader("Accept","application/json;version=1.2") .build(); } Response response = chain.proceed(requestBuilder.build()); Log.e("TokenInteceptor", "response.code=" + response.code()); if (isTokenExpired(response)) {//根据和服务端的约定判断token过期 Log.e("TokenInteceptor", "静默自动刷新Token,然后重新请求数据"); //同步请求方式,获取最新的Token SPDtadUtils.putString(UserApplication.getInstance(), "new_token", ""); String newToken = getNewToken(); if(TextUtils.isEmpty(newToken)) { UserApplication.getInstance().userLogout(true); throw new IOException(UserApplication.getInstance().getResources().getString(R.string.token_fail)); }else { //使用新的Token,创建新的请求 Request newRequest = chain.request() .newBuilder() .removeHeader(AppConstant.AUTH_HEADER) .addHeader(AppConstant.AUTH_HEADER, "bearer "+newToken) .addHeader("Accept","application/json;version=1.2") .build(); //重新请求 return chain.proceed(newRequest); } } return response; } private synchronized static String getNewToken() throws IOException{ Log.e("TAG", "执行上锁"); String refreshToken = SPDtadUtils.getString(UserApplication.getInstance(), "refreshToken"); if(TextUtils.isEmpty(refreshToken)) { return null; } String new_token = SPDtadUtils.getString(UserApplication.getInstance(), "new_token"); if(!TextUtils.isEmpty(new_token)) { return new_token; } TokenRefreshPostModel model = new TokenRefreshPostModel(); model.refresh_token = refreshToken; model.client_id = BuildConfig.CLIENT_ID; RequestBody body = RequestBody.create(AppConstant.MEDIA_TYPE_JSON, new Gson().toJson(model)); Request request = new Request.Builder().url(AppConstant.TOKEN_REFRESH).post(body).build(); Response newResponse = new OkHttpClient().newCall(request).execute(); Log.e("TAG", "刷新token"); if(newResponse.code() != 200) { //退出登录并返回到登录页面的逻辑 SPDtadUtils.putString(UserApplication.getInstance(), "refreshToken", ""); return null; } ResponseBody responseBody = newResponse.body(); TokenInfoModel tokenInfoModel = new Gson().fromJson(responseBody.string(), TokenInfoModel.class); UserUtils.saveToken(UserApplication.getInstance(), tokenInfoModel); SPDtadUtils.putString(UserApplication.getInstance(), "new_token", tokenInfoModel.getAccess_token()); Log.e("TAG", "存储token"); return tokenInfoModel.getAccess_token(); } private boolean isTokenExpired(Response response) { if(response.code() == 401) { ResponseBody body = response.body(); if (body != null){ try { MediaType mediaType = body.contentType(); if (mediaType != null) { if(isText(mediaType)) { String resp = body.string(); PostOkModel model = new Gson().fromJson(resp, PostOkModel.class); if(model.getCode() == 4601) { return true; } } } } catch (IOException e) { e.printStackTrace(); } } } return false; } private boolean isText(MediaType mediaType) { if (mediaType.type() != null && mediaType.type().equals("text")) { return true; } if (mediaType.subtype() != null) { if (mediaType.subtype().equals("json") || mediaType.subtype().equals("xml") || mediaType.subtype().equals("html") || mediaType.subtype().equals("webviewhtml") ) return true; } return false; }}
总结:以上就是我在项目中用的刷新token的方法。如果有不对的地方或者可以改进的地方,麻烦请告知,谢谢!
参考博文:
http://www.jianshu.com/p/8d1ee61bc2d2
http://www.jianshu.com/p/62ab11ddacc8
阅读全文
0 0
- OkHttp全局刷新token
- RxJava+Retrofit实现全局过期token自动刷新的实践
- Rxjava+Retrofit 实现全局过期 Token 自动刷新
- OkHttp 之 token使用
- 局部刷新,全局刷新
- RecyclerView+OkHttp加载刷新
- 封装okHttp 上下刷新
- 局部刷新与全局刷新
- OKhttp 拦截器Intercept token失效验证
- Rxjava2 + Retrofit2 + Okhttp + https 添加token
- UItableView 全局刷新,cell刷新,section刷新
- retrofit 刷新token并发处理
- RecyclerView+OkHttp的下拉刷新
- iOS APP开发全局token的使用
- jsp frameset 全局刷新和局部刷新
- struts 防刷新重复提交(Token)
- Struts1.x 防刷新重复提交(Token)
- Java 华为推送 Access Token过期刷新
- oracle数据库的学习
- Linux命令: cut命令的使用方法
- 调试opencv程序,怎么在vs运行下直接调到opencv的源码
- 一点一点学写Makefile(5)-获取文件所在路径
- 这是一个浮躁的时代
- OkHttp全局刷新token
- 在这个浮躁的社会,我要做好自己
- Floyd 算法 POJ 1125
- java学习 ——字符串<1>
- 张宇八套卷预测卷四
- 趣图:你能Get到笑点么?
- centos7 使用systemctl管理tomcat9
- 如果有人问你什么是大数据?不妨说说这10个典型的大数据案例
- 在mac上通过Homebrew安装redis