1. 程式人生 > >Retrofit 通過重新整理頭部Token解決token過期

Retrofit 通過重新整理頭部Token解決token過期

需求分析:

現在大多數應用也都有使用token來維持使用者登陸狀態,但後臺設定的token也都是有一定期限的,那麼不可避免的我們的Android應用會存在token過期的問題,那麼下面我們就來研究token過期的問題,來達到token失敗再次獲取token拿取資料的目的。

執行結果:

闡述,首先是驗證了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;
    }
}