Retrofit 通过刷新头部Token解决token过期

需求分析:

使用token来维持用户登陆状态是很常见的,但应当明确后台设置的token也都是有一定期限的,假如说是7天,那么我们的用户信息的获取必然是和token相绑定的,所以不可避免的我们的Android应用会存在token过期的问题,以下将一个开发案例来记录下如何自动刷新token的问题。

运行结果:

运行流程是获取相应的信息,首先是验证了token是否有效[包括一开始token不存在的情况去获取],发现是过期的或者无效的,紧接着去调用相应的api去获取登陆的token,之后再进行存储,然后请求成功。

核心代码,也都有注释。这里说明一点,获取token一定得是同步请求,异步会造成在返回对应的token之前已经进行了请求。

public class MyBaseApiRetrofit {
    private final OkHttpClient mClient;
    // 这里的token是从数据库中获得的-------------
    private String token = "Bearer default";

    public OkHttpClient getClient() {
        return mClient;
    }

    public MyBaseApiRetrofit(){
        //OkHttpClient
        OkHttpClient.Builder builder = new OkHttpClient.Builder();
        // -------- 在这里获得 token,通过数据库缓存 ********-----------
        if (BuildConfig.DEBUG) {
            // Log信息拦截器
            HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor();
            loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
            //设置 Debug Log 模式
            builder.addInterceptor(loggingInterceptor);
        }

        // 添加头部拦截器 并设定验证刷新 *******
        builder.addInterceptor(new Interceptor() {
            @Override
            public Response intercept(Chain chain) throws IOException {
                Request.Builder request = chain.request().newBuilder();
                //添加Token请求头 这里的token应当是从本地数据库中读取的 **********
                request.addHeader("Authorization", token);
                Response proceed = chain.proceed(request.build());
                //如果token过期 再去重新请求token 然后设置token的请求头 重新发起请求 用户无感
                if (isTokenExpired(proceed)){
                    String newHeaderToken = getNewToken();
                    //使用新的Token,创建新的请求
                    Request newRequest = chain.request().newBuilder()
                            .addHeader("Authorization", newHeaderToken)
                            .build();
                    return chain.proceed(newRequest);
                }
                return proceed;
            }
        });
        mClient = builder.build();
    }

    /**
     * 根据Response,判断Token是否失效
     * 401表示token过期
     * @param response
     * @return
     */
    private boolean isTokenExpired(Response response) {
        Log.e("状态码",response.code()+"---------------------");
        if (response.code() == 401) {
            return true;
        }
        return false;
    }

    /**
     * 这里可以考虑让后台提供一个接口,通过用户名直接返回一个token-----------------
     * @return
     * @throws IOException
     */
    @SuppressLint("CheckResult")
    private String getNewToken() throws IOException {
        LoginRequest loginRequest = new LoginRequest();
        loginRequest.setUsername("apple2");
        loginRequest.setPassword("123abc");
        OkHttpClient okHttpClient = new OkHttpClient();
        Gson gson = new Gson();
        String json = gson.toJson(loginRequest);
        RequestBody requestBody = FormBody.create(MediaType.parse("application/json; charset=utf-8")
                , json);
        Request request = new Request.Builder().url(MyApi.BASE_URL+"auth").post(requestBody).build();
        Call call = okHttpClient.newCall(request);
        String string = Objects.requireNonNull(call.execute().body()).string();
        MyLoginResponse loginResponse = JsonUtils.jsonToBean(string, MyLoginResponse.class);
        token = "Bearer "+loginResponse.getData().getToken();
        Log.e("token刷新结果",token);
        return token;
    }
}

总结

好了,一个解决token过期的小例子就是这样了,也是希望在点滴的工作与学习中取得长足的进步。

你可能感兴趣的:(常规案例记录)