OkHttp 之 token使用

来源:互联网 发布:1980年电影 知乎 编辑:程序博客网 时间:2024/05/29 07:52

原理解析

一般token的使用整体逻辑是这样的,登陆接口获取一个token 和一个刷新token用的refresh_token,在接下来的token请求中,所有的接口都需要携带token请求,以便服务端来验证请求的来源是合法的。这个token是有时效性的,服务端会给他一个时效性,一般设为2小时,在这个时间段内,这个token是有效的,可以请求成功,而过了这个时间段,这个token就失效了。这时候需要我们使用refresh_token 请求刷新token的接口来获取新的token 和 refresh_token,这样就可以源源不断的保持我们持有的token是有效合法的

设计思想

由于token过期这个事情应该是让用户无察觉的,所以我们android端需要偷偷的跑在后台,换句话说就是,在请求接口的时候,如果返回了TOKEN过期异常之后,我们需要立即再请求刷新接口,然后再使用新TOKEN 重新请求该接口,那么可以想想,这整个逻辑,如果每个接口都需要这么写,意味着我们会有很大的工作量,那么这是不科学的,所以我们需要使用一个拦截器,那样就很简单了接下来我放上我的代码,并根据代码解释下

代码解析

public class TokenInterceptor implements Interceptor {    private static final Charset UTF8 = Charset.forName("UTF-8");    @Override    public Response intercept(Chain chain) throws IOException {        Request request = chain.request();        //步骤一        String token = (String) SPUtils.get(AppContext.getInstance(), SPUtils.TOKEN, "");        if (!TextUtils.isEmpty(token) {            HttpUrl.Builder authorizedUrlBuilder = request.url()                    .newBuilder()                    .scheme(request.url().scheme())                    .host(request.url().host())                    .addQueryParameter("access_token", token);            request = request.newBuilder()                    .method(request.method(), request.body())                    .url(authorizedUrlBuilder.build())                    .build();        }        //步骤二        Response originalResponse = chain.proceed(request);        StatusVo func = getResult(originalResponse);        if (Status.TOKEN_Invalid.getCode() == func.getCode()) {            //步骤三            String newToken = getNewToken(loginBean);            if (TextUtils.isEmpty(newToken)) {                return originalResponse;            } else {                //步骤四                HttpUrl.Builder newUrlBuilder = request.url()                        .newBuilder()                        .scheme(request.url().scheme())                        .host(request.url().host())                        .removeAllQueryParameters("access_token")                        .addQueryParameter("access_token", newToken);                Request newRequest = request.newBuilder()                        .method(request.method(), request.body())                        .url(newUrlBuilder.build())                        .build();                return chain.proceed(newRequest);            }        }        return originalResponse;    }    /**     * 访问该接口,获取到数据,用来判断token     * @param originalResponse     * @return     * @throws IOException     */    private StatusVo getResult(final Response originalResponse) throws IOException {        ResponseBody responseBody = originalResponse.body();        BufferedSource source = responseBody.source();        source.request(Long.MAX_VALUE);        Buffer buffer = source.buffer();        Charset charset = UTF8;        MediaType contentType = responseBody.contentType();        if (contentType != null) {            charset = contentType.charset(UTF8);        }        String bodyString = buffer.clone().readString(charset);        Gson gson = new Gson();        //StatusVo 是个公共类,包含所有接口必定返回的code、msg 如果你们后台        //没有统一这么做,也可以直接从bodyString 取出可以判断token过期的数据        StatusVo func = gson.fromJson(bodyString, StatusVo.class);        return func;    }    //刷新token    private synchronized String getNewToken() throws IOException {        //获取刷新token        final String refreToken = (String) SPUtils.get(AppContext.getInstance(), SPUtils.REFRESH_TOKEN, "");;        //请求刷新token 接口获取新token        Call<RefreshTokenBean> objectObservable = Network.createService(NetWorkService.RefreshToken.class)                .refresh(refreToken);        RefreshTokenBean refreshTokenBean = objectObservable.execute().body();        //保存新token        final String newToken = refreshTokenBean.getResult().getData().getAccess_token();        final String newRefreshToken = refreshTokenBean.getResult().getData().getRefresh_token();        SPUtils.put(AppContext.getInstance(), SPUtils.TOKEN, newToken);        SPUtils.put(AppContext.getInstance(), SPUtils.REFRESH_TOKEN, newRefreshToken);        return newToken;    }}
  • 步骤一:获取本地Token,然后以参数的形式放进请求url中,在此处统一添加token,避免每个接口都要传token
  • 步骤二:对返回的数据进行预加载,对Token过期进行拦截处理
  • 步骤三:刷新Token,并保存
  • 步骤四:使用新的token 对Url进行重定向,再次请求

以上步骤就写好了该拦截器,接下来就把拦截器放进OkHttp里面了;

private OkHttpClient okHttpClient = new OkHttpClient.Builder()            .addInterceptor(new TokenInterceptor())            .build();

OK,以上就是OkHttp token的使用就可以搞定了