Android网络请求 —— Token拦截器(保证多个请求同时执行时候,成功拦截)

在App执行网络请求的场景中,经常需要用到Token作为合法访问身份识别码,设置到Header中传递给后台。且token往往是有效期的,这个时候,就需要用到 OkHttp的拦截器,对请求是否需要携带token做验证,并对token是否有效做验证,且在必要的时候重新获取合法token。

直接进入正题,token拦截器一共做了两件事情:1,对请求接口做判断,是否需要携带token;2,对token合法性做判断,并获取合法token。

1,判断请求接口是否需要携带token

(1)抽象拦截器,自定义用于判断是否需要token的Header字段:

public abstract class RxTokenInterceptor implements Interceptor {

    /**
     * IService接口中添加header,用于表示该接口是否必须携带token
     */
    public static final String HEADER_NEED_TOKEN = "NeedToken: true";
    public static final String HEADER_NO_NEED_TOKEN = "NeedToken: false";

    // ..............
}

(2)声明接口时候,加入自定义header标识

    @FormUrlEncoded
    @Headers(TokenInterceptor.HEADER_NO_NEED_TOKEN)
    @POST("api/v3/login")
    Observable> loginByPassword(@Field("username") String userName,
                                                   @Field("password") String password);

    @FormUrlEncoded
    @Headers(TokenInterceptor.HEADER_NEED_TOKEN)
    @POST("api/v3/login/password")
    Observable> setPassword(@Field("phoneNum") String phoneNum,
                                               @Field("password") String password,
                                               @Field("confirmPwd") String confirmPwd);

(3)抽象拦截器截取自定义header标识,做判断。并开放getToken抽象方法给子类。

public abstract class RxTokenInterceptor implements Interceptor {

    /**
     * IService接口中添加header,用于表示该接口是否必须携带token
     */
    public static final String HEADER_NEED_TOKEN = "NeedToken: true";
    public static final String HEADER_NO_NEED_TOKEN = "NeedToken: false";

    @Override
    public Response intercept(Chain chain) throws IOException {
        Request original = chain.request();
        Request.Builder builder = original
                .newBuilder();
        String needToken = original.header("NeedToken");
        if (needToken == null || needToken.equals("true")) {
            builder.header("Authorization", getToken());
        }
        Request request = builder
                .removeHeader("NeedToken")
                .method(original.method(), original.body())
                .build();
        return chain.proceed(request);
    }

    protected abstract String getToken();
}

2,对token合法性做判断,并获取合法token。

Token拦截规则:

1.当前未登录:取消正在执行的所有请求,跳转登录;

2.当前已登录:

(1)token未过期:返回token

(2)token已过期:重新刷token

        1)刷新成功:更新本地token并返回

        2)刷新失败:取消正在执行的所有请求,弹窗重登陆 -> 跳转登录;

为保证 取消正在执行的所有请求 到 跳转登录页 过程中另外有新的请求产生,导致多次跳转登录页情况,建议把LoginActivity设置SingleTop

直接上源码:

/**
 * Token拦截:
 * 1.当前未登录:取消正在执行的所有请求,跳转登录;
 * 2.当前已登录:
 * (1)token未过期:返回token
 * (2)token已过期:重新刷token
 * 1)刷新成功:更新本地token并返回
 * 2)刷新失败:取消正在执行的所有请求,弹窗重登陆 -> 跳转登录;
 * 为保证 取消正在执行的所有请求 到 跳转登录页 过程中另外有新的请求产生,导致多次跳转登录页情况,建议把LoginActivity设置SingleTop
 *
 * @author Created by qiang.hou on 2018/12/11.
 * @version 1.0
 */
public class TokenInterceptor extends RxTokenInterceptor {
    @Override
    protected String getToken() {
        String tokenValue = "";

        if (!isLoginStatus()) {
            // 取消正在执行的所有请求
            RxRetrofitUtils.getInstance().cancelAll();
            // go to login
            return tokenValue;
        }

        if (isExpires()) {
            Call tokenCall = RxRetrofitUtils.getInstance()
                    .create(ICommonService.class)
                    .refreshToken("refresh_token",
                            SharedManager.getInstance().getValue(SharedManager.KEY_REFRESH_TOKEN_VALUE, ""));
            BeanForRefreshToken data = null;
            try {
                data = tokenCall.execute().body();
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                if (data != null) {
                    SharedManager.getInstance().refreshToken(data);
                    tokenValue = data.tokenType + " " + data.value;
                } else {
                    //获取不到token直接清除登录信息
                    SharedManager.getInstance().clearUserData();
                    // 取消正在执行的所有请求
                    RxRetrofitUtils.getInstance().cancelAll();
                    // show dialog and goto login
                    showDialogAndGoToLogin();
                }
            }
        } else {
            tokenValue = SharedManager.getInstance().getValue(SharedManager.KEY_TOKEN_TYPE, "")
                    + " "
                    + SharedManager.getInstance().getValue(SharedManager.KEY_TOKEN_VALUE, "");
        }

        return tokenValue;
    }

    /**
     * show goto login dialog
     */
    private void showDialogAndGoToLogin() {

    }

    /**
     * token是否过了有效期
     *
     * @return boolean
     */
    private boolean isExpires() {
        long expiresTime = SharedManager.getInstance().getValue(SharedManager.KEY_TOKEN_EXPIRES_TIME, 0L);

        return System.currentTimeMillis() > expiresTime;
    }

    /**
     * 是否处于登录状态
     *
     * @return boolean
     */
    private boolean isLoginStatus() {
        return false;
    }
}

 

 

 

 

 

你可能感兴趣的:(Android,常见问题)