android - 使用 Okhttp 的验证器(以及 RetroFit、RxJava 和 Dagger2)实现全局强制注销
问题描述
任务
我有一种情况,如果刷新令牌请求返回 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 You have not authorized”消息,而是显示一个 toast 说“Session Expired”
请求拦截器
@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 后运行额外的时间,该 API 在应该发生两次的事情之后运行。
据我了解,身份验证器应该刚刚执行了注销服务,而拦截器应该已经开始工作了。
但是,身份验证器执行以下操作
1) 尝试获取新的访问令牌
2)失败并调用注销API(调用Interceptor并广播注销)
3)失败并调用注销API(调用拦截器并广播注销)
4) 结束
我知道我可能会破坏 OkHttps 身份验证机制中的某些内容,但是我可以使用哪些其他方法来实现强制注销,而无需对所有 API 编写 401 检查?
对长长的问题深表歉意。
解决方案
推荐阅读
- javascript - 如何从javascript中提取字符串
- python - python 在初始化超过 31 个元素时出现问题
- c - 检查是否设置或清除了多个位
- ios - 自定义嵌套对象的 Swift 编码技术?
- python - Django - csv.reader 和 save()/update
- python - 从图像中去除噪声,使其准备好使用 python 进行 tesseract ocr 并打开 cv
- java - startActivity :哪种方法更好,为什么?
- python - Ubuntu中的Python多处理内存泄漏,但在Windows中没有
- ruby-on-rails - has_and_belongs_to_many 关联的唯一性验证
- configuration - 如何使用 filebeat 读取 CPU 使用率、RAM 使用率和磁盘使用率?