我正在尝试使用Retrofit(2.0.0-beta3),但是当使用Authenticator添加令牌时,我似乎无法从同步调用中获取数据。我们在后端的日志记录只显示了很多登录尝试,但我无法从正文中获取实际添加到标题的数据。
public static class TokenAuthenticator implements Authenticator {
@Override
public Request authenticate(Route route, Response response) throws IOException {
// Refresh your access_token using a synchronous api request
UserService userService = createService(UserService.class);
Call<Session> call = userService.emailLogin(new Credentials("handle", "pass"));
// This call is made correctly, as it shows up on the back-end.
Session body = call.execute().body();
// This line is never hit.
Logger.d("Session token: " + body.token);
// Add new header to rejected request and retry it
return response.request().newBuilder()
.header("Auth-Token", body.token)
.build();
}
}
我不太确定为什么它甚至不打印任何东西。关于如何解决这个问题的任何提示都将非常感谢,感谢您抽出宝贵时间提供帮助。
这些是我一直在阅读的有关如何实施Retrofit的资料。
使用身份验证器:
使用Retrofit 2进行同步调用:
答案 0 :(得分:8)
我设法使用TokenAuthenticator和拦截器获得了一个不错的解决方案,并且我认为我可以分享这个想法,因为它可以帮助其他人。
添加&#39; TokenInterceptor&#39;处理将标记添加到标题的类是存在的标记,以及“标记验证器”#39; TokenAuthenticator&#39; class处理没有令牌的情况,我们需要生成一个。
我确信有更好的方法可以实现这一点,但我认为这是一个很好的起点。
public static class TokenAuthenticator implements Authenticator {
@Override
public Request authenticate( Route route, Response response) throws IOException {
...
Session body = call.execute().body();
Logger.d("Session token: " + body.token);
// Storing the token somewhere.
session.token = body.token;
...
}
private static class TokenInterceptor implements Interceptor {
@Override
public Response intercept( Chain chain ) throws IOException {
Request originalRequest = chain.request();
// Nothing to add to intercepted request if:
// a) Authorization value is empty because user is not logged in yet
// b) There is already a header with updated Authorization value
if (authorizationTokenIsEmpty() || alreadyHasAuthorizationHeader(originalRequest)) {
return chain.proceed(originalRequest);
}
// Add authorization header with updated authorization value to intercepted request
Request authorisedRequest = originalRequest.newBuilder()
.header("Auth-Token", session.token )
.build();
return chain.proceed(authorisedRequest);
}
}
来源:
答案 1 :(得分:5)
我有类似的身份验证器,它适用于2.0.0-beta2。
如果您从Authenticator获得了大量登录尝试,我建议您确保在进行同步调用时,您没有使用Authenticator进行该调用。 如果您的“emailLogin”失败,那可能会循环播出。
另外我建议添加loggingInterceptor以查看服务器的所有流量:Logging with Retrofit 2
答案 2 :(得分:0)
我知道这是一个迟来的答案,但是对于仍然想知道如何使用 Retrofit 2 Authenticator 添加/刷新令牌的任何人,这是一个可行的解决方案:
注意:preferenceHelper是您的“首选项管理器”类,您可以在其中设置/获取共享的首选项。
public class AuthenticationHelper implements Authenticator {
private static final String HEADER_AUTHORIZATION = "Authorization";
private static final int REFRESH_TOKEN_FAIL = 403;
private Context context;
AuthenticationHelper(@ApplicationContext Context context) {
this.context = context;
}
@Override
public Request authenticate(@NonNull Route route, @NonNull Response response) throws IOException {
// We need to have a token in order to refresh it.
String token = preferencesHelper.getAccessToken();
if (token == null)
return null;
synchronized (this) {
String newToken = preferencesHelper.getAccessToken();
if (newToken == null)
return null;
// Check if the request made was previously made as an authenticated request.
if (response.request().header(HEADER_AUTHORIZATION) != null) {
// If the token has changed since the request was made, use the new token.
if (!newToken.equals(token)) {
return response.request()
.newBuilder()
.removeHeader(HEADER_AUTHORIZATION)
.addHeader(HEADER_AUTHORIZATION, "Bearer " + newToken)
.build();
}
JsonObject refreshObject = new JsonObject();
refreshObject.addProperty("refreshToken", preferencesHelper.getRefreshToken());
retrofit2.Response<UserToken> tokenResponse = apiService.refreshToken(refreshObject).execute();
if (tokenResponse.isSuccessful()) {
UserToken userToken = tokenResponse.body();
if (userToken == null)
return null;
preferencesHelper.saveAccessToken(userToken.getToken());
preferencesHelper.saveRefreshToken(userToken.getRefreshToken());
// Retry the request with the new token.
return response.request()
.newBuilder()
.removeHeader(HEADER_AUTHORIZATION)
.addHeader(HEADER_AUTHORIZATION, "Bearer " + userToken.getToken())
.build();
} else {
if (tokenResponse.code() == REFRESH_TOKEN_FAIL) {
logoutUser();
}
}
}
}
return null;
}
private void logoutUser() {
// logout user
}
}
还请注意: