互联网不稳定时处理访问令牌过期
Handling access token expiry when internet is unstable
我正在使用 Retrofit2 作为 Android 的 HTTP 客户端。该应用程序使用访问令牌和刷新令牌与后端通信。
场景1:access-token过期,api调用失败并返回401错误码,然后我使用Authenticator使用refresh-token获取一对新的access-token并刷新-token 并继续为失败的调用使用新的访问令牌。这一切都适用于稳定的互联网连接
场景2:现在考虑一下,互联网不稳定,经常断断续续。互联网就在那里,api 调用因访问令牌过期而失败,
应用程序使用刷新令牌进行登录调用以获取一对新的访问令牌和刷新令牌。但在我获得成功 200 之前,登录呼叫互联网掉线了。
现在互联网恢复了,我的应用程序开始再次触发 api 调用并获得 401,然后使用刷新令牌触发新的登录调用。这就是问题所在,后端已经更新了新的访问和刷新令牌,但应用程序从未在互联网关闭时收到它。因此,我拥有的刷新令牌不再有效(因为已经在后端创建了一对新的并刷新了旧的)
不确定我应该如何处理这种情况?
这是我的验证器 class:
public class MyAuthenticator implements Authenticator {
Context context;
public MyAuthenticator(Context context) {
this.context = context;
}
@Nullable
@Override
public Request authenticate(Route route, Response response) throws IOException {
Retrofit client = new Retrofit.Builder()
.baseUrl(Manager.API_BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build();
ApiService service = client.create(ApiService.class);
SharedPreferenceManager sharedPreferenceManager = new SharedPreferenceManager(context);
String refreshToken = sharedPreferenceManager.getRefreshToken(context);
AuthRequest authRequest = new AuthRequest();
authRequest.grant_type = "refresh_token";
authRequest.refresh_token = refreshToken;
Call<authResponse> refreshTokenResult = service.refreshToken(authRequest);
retrofit2.Response accessTokenResponse = refreshTokenResult.execute();
//check if response equals 400 , mean empty response
if (accessTokenResponse.isSuccessful()) {
AuthResponse refreshResult = (AuthResponse) accessTokenResponse.body();
//save new access and refresh token
sharedPreferenceManager.writeLoginResponse(context, refreshResult);
// then create a new request and modify it accordingly using the new token
return response.request().newBuilder()
.header("Authorization", "Bearer " + refreshResult.access_token)
.build();
} else {
LoginActivity_.intent(context).flags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK).start();
return null;
}
}
}
不确定我遗漏了什么以及我应该如何解决这个问题。
你不能在客户端对此做任何事情。
您要做的是新代币的一次性交付,which is impossible。相反,您应该设计至少一次交付。
您必须为这种情况准备服务器,即它也应该接受旧的刷新令牌,直到它至少收到一次新的访问令牌或刷新令牌。
到那时,服务器无法确定客户端是否收到了新令牌。
我正在使用 Retrofit2 作为 Android 的 HTTP 客户端。该应用程序使用访问令牌和刷新令牌与后端通信。
场景1:access-token过期,api调用失败并返回401错误码,然后我使用Authenticator使用refresh-token获取一对新的access-token并刷新-token 并继续为失败的调用使用新的访问令牌。这一切都适用于稳定的互联网连接
场景2:现在考虑一下,互联网不稳定,经常断断续续。互联网就在那里,api 调用因访问令牌过期而失败, 应用程序使用刷新令牌进行登录调用以获取一对新的访问令牌和刷新令牌。但在我获得成功 200 之前,登录呼叫互联网掉线了。 现在互联网恢复了,我的应用程序开始再次触发 api 调用并获得 401,然后使用刷新令牌触发新的登录调用。这就是问题所在,后端已经更新了新的访问和刷新令牌,但应用程序从未在互联网关闭时收到它。因此,我拥有的刷新令牌不再有效(因为已经在后端创建了一对新的并刷新了旧的)
不确定我应该如何处理这种情况? 这是我的验证器 class:
public class MyAuthenticator implements Authenticator {
Context context;
public MyAuthenticator(Context context) {
this.context = context;
}
@Nullable
@Override
public Request authenticate(Route route, Response response) throws IOException {
Retrofit client = new Retrofit.Builder()
.baseUrl(Manager.API_BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build();
ApiService service = client.create(ApiService.class);
SharedPreferenceManager sharedPreferenceManager = new SharedPreferenceManager(context);
String refreshToken = sharedPreferenceManager.getRefreshToken(context);
AuthRequest authRequest = new AuthRequest();
authRequest.grant_type = "refresh_token";
authRequest.refresh_token = refreshToken;
Call<authResponse> refreshTokenResult = service.refreshToken(authRequest);
retrofit2.Response accessTokenResponse = refreshTokenResult.execute();
//check if response equals 400 , mean empty response
if (accessTokenResponse.isSuccessful()) {
AuthResponse refreshResult = (AuthResponse) accessTokenResponse.body();
//save new access and refresh token
sharedPreferenceManager.writeLoginResponse(context, refreshResult);
// then create a new request and modify it accordingly using the new token
return response.request().newBuilder()
.header("Authorization", "Bearer " + refreshResult.access_token)
.build();
} else {
LoginActivity_.intent(context).flags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK).start();
return null;
}
}
}
不确定我遗漏了什么以及我应该如何解决这个问题。
你不能在客户端对此做任何事情。
您要做的是新代币的一次性交付,which is impossible。相反,您应该设计至少一次交付。
您必须为这种情况准备服务器,即它也应该接受旧的刷新令牌,直到它至少收到一次新的访问令牌或刷新令牌。
到那时,服务器无法确定客户端是否收到了新令牌。