OkHttp 之 token使用

原理解析

一般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 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的使用就可以搞定了

你可能感兴趣的:(网络请求)