使用Okhttp的身份验证器(以及RetroFit,RxJava和Dagger2)实现全球部队登出

时间:2018-08-12 06:49:23

标签: android oauth-2.0 retrofit2 okhttp3

任务

我遇到的情况是,如果刷新令牌请求返回401,我将通过从房间和内存中清除用户来强制注销。我想从Authenticator或Interceptor内部实现此目的,因此我不必检查401作为对每个呼叫的响应。

身份验证器

public Request authenticate(Route route, Response response) throws IOException {
//        if (responseCount(response) >= 3) {
//            return null;
//        }
//
        UserCredentials userCredentials = new
                UserCredentials().
                CreateRefreshTokenRequest("refresh_token",
                        requestHeaders.getAccessToken().getRefreshToken(),
                        oAuthClient.getClientId(),
                        oAuthClient.getClientSecret());
        Request.Builder builder = response.request().newBuilder();

        if (accountsServicesHolder.getAccountsServices() == null)
            return null;

        //this HAS TO BE a Synchronous process. The usual RXjava shenanigans can't be applied here.
        try {
           //Synchronous call to get new token
            AccessToken accessToken = accountsServicesHolder.
                    getAccountsServices().
                    refreshToken(userCredentials.toMap()).
                    blockingGet();


            //persist the token in the db
            //userDao.save()

            //persist the token in memory

            //send an updated version to the backend
            builder.header("Authorization", "Bearer " + accessToken.getAccessToken());
        } catch (Exception ex) {
            if (ex instanceof HttpException) { 
                return builder.
                        url(linksProvider.getProductionUrl().concat(logoutEndpoint)).
                        build(); //Redirecting this authenticator to a logout ws so that we do not get a 401 . Something goes wrong here 
            }
        }

        return builder.build();
    }

如您所见,如果我们没有基于刷新令牌的令牌,那么我很狡猾地在构建器中插入一个新URL。这样一来,我就不会出现401冒泡到最初发出呼叫的位置的情况。我不希望用户收到“ 401您尚未授权”消息,而是显示一个吐司说“会话已过期”

请求拦截器

@Override
public Response intercept(Chain chain) throws IOException {
    Request original = chain.request();
    Request.Builder builder = original.newBuilder().
            header("Authorization", "Bearer " + requestHeaders.getAccessToken().getAccessToken()).
            header("Accept-Language", requestHeaders.getLanguage()).
            method(original.method(), original.body());
    Request newRequest = builder.build();

    Response response = chain.proceed(newRequest);

    if (response.code() == 200
            && response.request().url().toString().contains("logout")) {

        forceUserOut();
    }
    return response;
}

forceUserOut方法向系统广播已发生注销。 由于我们已经针对401进行了保护,因此不会向用户显示任何错误。

问题

好的,现在我们来解决问题。毕竟我以为我被打扰的地方可能并不那么聪明。身份验证器在调用注销API后再运行一段额外的时间,该时间在应该发生两次的事件之后运行。

据我了解,身份验证器应该刚刚执行了注销服务,然后拦截器应该已经开始执行其工作。

但是,身份验证器执行以下操作

1)尝试获取新的访问令牌

2)失败并调用注销API(调用拦截器并广播注销)

3)失败并调用注销API(调用拦截器并广播注销)

4)结束

我知道我可能会破坏OkHttps身份验证机制中的某些内容,但是我可以使用什么其他方法来实现强制注销,而不必以对所有API进行401检查的方式进行?

对于这个长期的问题深表歉意。

0 个答案:

没有答案