web-dev-qa-db-ja.com

Android --Retrofit2-オーセンティケーターの結果

Retrofit(2.0.0-beta3)を使用しようとしていますが、オーセンティケーターを使用してトークンを追加すると、同期呼び出しからデータを取得できないようです。バックエンドでのログには多くのログイン試行が表示されますが、本文からデータを取得して実際にヘッダーに追加することはできません。

    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で同期呼び出しを行う:

6
Advice-Dog

私は同様のオーセンティケーターを持っており、2.0.0-beta2で動作します。

オーセンティケーターから多くのログイン試行を取得する場合は、同期呼び出しを行うときに、その呼び出しでオーセンティケーターを使用していないことを確認することをお勧めします。 「emailLogin」も失敗すると、ループが発生する可能性があります。

また、loggingInterceptorを追加して、サーバーへのすべてのトラフィックを確認することをお勧めします。 Retrofit 2でのロギング

5
Jari Kokkonen

私はTokenAuthenticatorとInterceptorを使用してまともなソリューションを得ることができ、他の人に役立つかもしれないので、アイデアを共有したいと思いました。

ヘッダーへのトークンの追加を処理する「TokenInterceptor」クラスの追加はトークンが存在することであり、「TokenAuthenticator」クラスはトークンがない場合を処理するため、トークンを生成する必要があります。

これを実装するためのより良い方法がいくつかあると確信していますが、それは良い出発点だと思います。

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);
    }
}

ソース:

http://lgvalle.xyz/2015/07/27/okhttp-authentication/

8
Advice-Dog

私はそれが遅い答えであることを知っていますが、Retrofit 2 Authenticatorでトークンを追加/更新する方法をまだ疑問に思っている人のために、ここに実用的な解決策があります:

注:preferenceHelperは、共有設定を設定/取得するPreferenceManagerクラスです。

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
    }
}

また注意してください:

  1. preferencesHelperとapiServiceを何らかの方法で提供する必要があります。
  2. これは、すべてのシステムとAPIで機能する例ではありませんが、Retrofit 2 Authenticatorを使用してトークンの追加と更新を行う方法の例です。
1
Alex