请求加密,响应数据解密,过期自动刷新并且重新请求接口
2016-10-09 11:46
471 查看
此博客是参考http://blog.csdn.net/jdsjlzx/article/details/52442113
并且增加加密和解密的操作
转换器是在converter包里面
在GsonConverterFactory类里面
对应的加密数据,我统一在响应解析器里面做处理
这里面做了解密操作,每次请求都会查看是否有新的key以及token,如果存在就进行缓存操作,还有就是对返回码做了一定的处理,后天返回10000代表token失效,直接向上面抛异常TokenInvalidException()
注释写的很详细了
整个请求逻辑是这样的(每次请求都会有加密和解密操作)
1. 首次请求中,正常的请求,返回数据解密后发现token过期,抛出TokenInvalidException;
2. 拦截token过期异常,同步请求获取新的token,在响应转换器里面做了token和key值的保存,最后返回一个just(true),并把标志位设置为true,重试请求原先的Observable;
3. 判断标志位,更新token,在updateMethodToken()方法中,使用第一次的加密key,解密参数,然后做token数据的更新,使用的新的可以进行加密,再次发送请求;
并且增加加密和解密的操作
1.先熟悉一下retrofit2.0+中的gson转换器
最开始的来看看主要的代码转换器是在converter包里面
在GsonConverterFactory类里面
@Override public Converter<ResponseBody, ?> responseBodyConverter(final Type type, Annotation[] annotations, Retrofit retrofit) { Type newType = new ParameterizedType() { @Override public Type[] getActualTypeArguments() { return new Type[] { type }; } @Override public Type getOwnerType() { return null; } @Override public Type getRawType() { return BaseResponse.class; } }; TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(newType)); if (String.class.equals(type)) { //响应如果是加密数据 return new StringConverterFactory<>(adapter); }else{ //响应是json对象 return new GsonResponseBodyConverter<>(gson, adapter); } }
对应的加密数据,我统一在响应解析器里面做处理
public class StringConverterFactory<T> implements Converter<ResponseBody, Object> { private final TypeAdapter<T> adapter; StringConverterFactory(TypeAdapter<T> adapter) { this.adapter = adapter; } @Override public Object convert(ResponseBody value) throws IOException { try { String aseKey= UserCache.getAesSecretKey(); LogUtils.d("解密秘钥aseKey = " + aseKey); String data = null; try { data = AES.dencrypt(value.string(), aseKey); LogUtils.e("返回数据:"+data); BaseResponse baseResponse = new Gson().fromJson(data, BaseResponse.class); if(!StringUtils.isEmpty(baseResponse.getNewAesKey())){ //保证AESkey在缓存中 LogUtils.i("获得新的key====="+baseResponse.getNewAesKey()); //缓存中获取秘钥 UserCache.saveAesSecretKey(baseResponse.getNewAesKey()); } if (baseResponse.isSuccess()) { //保存Token if(!StringUtils.isEmpty(baseResponse.getToken())){ LogUtils.i("保存token====="+baseResponse.getToken()); UserCache.saveToken(baseResponse.getToken()); } } } catch (Exception e) { e.printStackTrace(); } BaseResponse apiModel = (BaseResponse) adapter.fromJson(data); if (apiModel.getErrCode() == ErrorCode.TOKEN_NOT_EXIST) { throw new TokenNotExistException(); } else if (apiModel.getErrCode() == ErrorCode.TOKEN_INVALID) { //token失效保存原先的key UserCache.saveFirstAesSecretKey(aseKey); throw new TokenInvalidException(); } else if (!apiModel.isSuccess()) { return null; } else if (apiModel.isSuccess()) { return apiModel.data; }else{ BaseResponse baseResponse = new Gson().fromJson(value.string(), BaseResponse.class); return baseResponse; } } finally { value.close(); } } }
这里面做了解密操作,每次请求都会查看是否有新的key以及token,如果存在就进行缓存操作,还有就是对返回码做了一定的处理,后天返回10000代表token失效,直接向上面抛异常TokenInvalidException()
2.动态代理InvocationHandler方法,最关键的类
重试机制使用的是Rxjava中的retryWhen操作符public class ProxyHandler implements InvocationHandler { private final static String JSON = "json"; private Throwable mRefreshTokenError = null; //是否需要刷新token private boolean mIsTokenNeedRefresh; private Object mProxyObject; private String encrypt; public ProxyHandler(Object proxyObject) { mProxyObject = proxyObject; } @Override public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable { return Observable.just(null).flatMap(new Func1<Object, Observable<?>>() { @Override public Observable<?> call(Object o) { try { try { if (mIsTokenNeedRefresh) { //刷新token请求 updateMethodToken(method, args); } //首次请求 return (Observable<?>) method.invoke(mProxyObject, args); } catch (InvocationTargetException e) { e.printStackTrace(); } } catch (IllegalAccessException e) { e.printStackTrace(); } return null; } }).retryWhen(new Func1<Observable<? extends Throwable>, Observable<?>>() { @Override public Observable<?> call(Observable<? extends Throwable> observable) { return observable.flatMap(new Func1<Throwable, Observable<?>>() { @Override public Observable<?> call(Throwable throwable) { //获得从上一个请求带过来的异常信息 if (throwable instanceof TokenInvalidException) { //token过期 return refreshTokenWhenTokenInvalid(); } else if (throwable instanceof TokenNotExistException) { //token不存在,目前没做处理 return Observable.error(throwable); } //其他异常 return Observable.error(throwable); } }); } }); } /** * 请求token数据 * @return Observable */ private Observable<?> refreshTokenWhenTokenInvalid() { synchronized (ProxyHandler.class) { UserApi.updateToken(AppContext.getContext(), "1", new Subscriber<String>() { @Override public void onCompleted() { } @Override public void onError(Throwable e) { mRefreshTokenError = e; } @Override public void onNext(String s) { //设置标志位为true mIsTokenNeedRefresh = true; } }); if (mRefreshTokenError != null) { //直接抛异常 return Observable.error(mRefreshTokenError); } else { //无异常,重新请求上一个请求 return Observable.just(true); } } } /** * 更新token,并且做了加密解密操作 */ private void updateMethodToken(Method method, Object[] args) { if (mIsTokenNeedRefresh && !TextUtils.isEmpty(UserCache.getToken())) { Annotation[][] annotationsArray = method.getParameterAnnotations(); Annotation[] annotations; if (annotationsArray != null && annotationsArray.length > 0) { for (int i = 0; i < annotationsArray.length; i++) { annotations = annotationsArray[i]; for (Annotation annotation : annotations) { if (annotation instanceof Query) { String json = ((Query) annotation).value(); if (JSON.equals(json)) { //替换新的token LogUtils.d("替换新的token+++json="+args[i].toString()); //1.先解密数据 缓存中获取秘钥 String firstAesKey = UserCache.getFirstAesSecretKey(); try { LogUtils.d("第二次请求中解密使用首次请求的秘钥aseKey = " + firstAesKey); String response= AES.dencrypt(args[i].toString(), firstAesKey); LogUtils.e("旧的json="+response); BaseRequest baseResponse = new Gson().fromJson(response, BaseRequest.class); baseResponse.setToken(UserCache.getToken()); String newJson = new Gson().toJson(baseResponse); String aseKey= UserCache.getAesSecretKey(); LogUtils.d("加密的秘钥aseKey = " + aseKey); UserCache.saveFirstAesSecretKey(aseKey); LogUtils.e("newJson="+newJson); encrypt = AES.encrypt(newJson, aseKey); } catch (Exception e) { e.printStackTrace(); } args[i] = encrypt; } } } } } mIsTokenNeedRefresh = false; } } }
注释写的很详细了
整个请求逻辑是这样的(每次请求都会有加密和解密操作)
1. 首次请求中,正常的请求,返回数据解密后发现token过期,抛出TokenInvalidException;
2. 拦截token过期异常,同步请求获取新的token,在响应转换器里面做了token和key值的保存,最后返回一个just(true),并把标志位设置为true,重试请求原先的Observable;
3. 判断标志位,更新token,在updateMethodToken()方法中,使用第一次的加密key,解密参数,然后做token数据的更新,使用的新的可以进行加密,再次发送请求;
相关文章推荐
- Retrofit Token过期自动刷新并重新请求接口
- angular实现页面跳转,并且刷新页面(重新请求后台接口)
- Json数据异步绑定到界面的Table并且自动刷新
- 重新想象 Windows 8 Store Apps (32) - 加密解密: 非对称算法, 数据转换的辅助类
- 项目背景: 1、接口URL:http://192.168.xx.xx:8080/mserver/rest/ms 2、接口参数:data=xxxxx&key=xxxxx,数据是加密的 3、请求方式
- PHP通过OpenSSL生成证书、密钥并且加密解密数据
- Json数据异步绑定到界面的Table并且自动刷新原理及代码
- 请求响应/加密解密时一个需要注意的小问题
- PHP通过OpenSSL生成证书、密钥并且加密解密数据,以及公钥,私钥和数字签名的理解
- java httpServer端接受post请求数据并使用3DES+base64加密解密demo希望能够对您有帮助
- 基于springmvc实现的接口进行json数据自动加解密
- 重新想象 Windows 8 Store Apps (32) - 加密解密: 非对称算法, 数据转换的辅助类
- 关于url请求和json数据的响应的理解和接口的压力测试
- Json数据异步绑定到界面的Table并且自动刷新 .
- JMeter BeanShell 的使用-请求加密-返回自动解密处理
- as3.0利用DES和AES对数据进行加密和解密并且与php端加密匹配!
- PHP通过OpenSSL生成证书、密钥并且加密解密数据
- 处理HTTP响应(响应码、响应头、请求重定向、自动刷新/跳转)
- Json数据异步绑定到界面的Table并且自动刷新
- retrofit 自定义请求参数加密 和自定义响应解密 带你走出那些坑