在开发电商类项目的时候,都要保持登陆状态,避免用户的反复登陆,当然要实现这种逻辑有很多种方法,我就说下我在项目中用拦截器实现的自动登陆
我们项目是直接将token信息放到header里,token的有效期是三十分钟,如果token失效,再根据服务器返回来的code,来判断,再通过自动登陆接口,获取新的token放到header里,并生成新的request 请求服务器,如果你的项目服务器也是这样操作的,可以借鉴下我的代码:
先看下自己创建的服务器交互类,里面一般会封装服务器请求接口和单利实例,最主要的还是创建拦截器:
//设置拦截器,对请求参数做签名处理 Interceptor interceptor = new Interceptor() { @Override public Response intercept(Chain chain) throws IOException { Request request = chain.request(); // 新的请求 Request newRequest = null; String token = SpUtil.getInstance(context).getStringValue("token"); if (oldBody instanceof FormBody) { if (!TextUtils.isEmpty(token)) { //token没失效,继续用 newRequest = request.newBuilder().url(request.url()).post(formBuilder.build()).header("token", token).build(); } else{ newRequest = request.newBuilder().url(request.url()).post(formBuilder.build()).build(); } } //以下代码是签名之后需要使用的代码,不需要签名请注释 Response response = chain.proceed(newRequest); return response; } };第一个拦截器,最主要的目的就是把token放到请求头里面,不用每次请求的时候都在去加上token;
private class TokenInterceptor implements Interceptor { private Context context; public TokenInterceptor(Context context){ this.context = context; } @Override public Response intercept(Chain chain) throws IOException { Request request = chain.request(); // try the request Response originalResponse = chain.proceed(request); /**通过如下的办法曲线取到请求完成的数据 * * 原本想通过 originalResponse.body().string() * 去取到请求完成的数据,但是一直报错,不知道是okhttp的bug还是操作不当 * 取到请求完成的数据后,根据特定的判断条件去判断token过期 */ ResponseBody responseBody = originalResponse.body(); BufferedSource source = responseBody.source(); source.request(Long.MAX_VALUE); // Buffer the entire body. Buffer buffer = source.buffer(); Charset charset = UTF8; MediaType contentType = responseBody.contentType(); if (contentType != null) { charset = contentType.charset(UTF8); } String bodyString = buffer.clone().readString(charset); ResultVo vo = GsonUtil.deser(bodyString, ResultVo.class); if (vo.result == 0) { //token失效 LogUtil.e("静默自动刷新Token,然后重新请求数据"); String code = SpUtil.getInstance(context).getStringValue("code"); if (!TextUtils.isEmpty(code)){ // 通过一个特定的接口获取新的token,此处要用到同步的retrofit请求 Call<ResultVo> call = NetworkService.getInstance().getAPI().autoLogin(code); //要用retrofit的同步方式 ResultVo response = call.execute().body(); if(response.result==0){ Intent intent = new Intent(context,LoginActivity.class); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); context.startActivity(intent); return originalResponse; }else{ String newToken = call.clone().execute().body().token; //call只能有一个 LogUtil.e("newToken"+newToken); SpUtil.getInstance(context).setValue("token",newToken); // create a new request and modify it accordingly using the new token Request newRequest = chain.request().newBuilder().header("token", newToken).build(); // retry the request // originalResponse.body().close(); return chain.proceed(newRequest); } } } return originalResponse; } }
这是自己建的token拦截器,实现Interceptor接口,然后根据拿到的response解析到里面的我们想要的数据,再根据服务器返回的result来进行判断,这里的0是服务器返回的,所以具体情况具体分析,这里我是用sharepreference来保存token和code,是有隐患的,所以可以用其他方法替代,但是思想一致,拿到我们在登陆的时候服务器返回的code,调用自动登陆接口,前提是用户已经登陆过,这时候再判断下result,因为可能用户会在PC 或者其他方式修改过密码,确认result无误后,我们在保存新token的同时,将新的token放到请求头里,并传给服务器,就完成了简单的自动登陆功能,但此方法有局限性且用SP 有隐患。