web-dev-qa-db-ja.com

アカウントオーセンティケーターで認証トークンの有効期限が切れている場合は、更新トークンを使用します

AccountManagerを使用してユーザーのアカウントを保存するアプリがあります。ユーザーは、OAuth2.0パスワード-ユーザー名資格情報フローを使用して、my REST APIを介してログインおよびサインアップします。

ユーザーが受け取るアクセストークンは2時間で期限切れになり、再び期限切れになるまで更新する必要があります。

このさわやかな機能をオーセンティケーターに実装する必要があります。

次のフィールドを持つAccessTokenというモデルがあります。

String accessToken, String tokenType, Long expiresIn, String refreshToken, String scope, Long createdAt

そのため、現在、getAuthTokenクラスのAccountAuthenticatorメソッドで、このAccessTokenオブジェクトを受け取り、そのaccessTokenフィールドをアカウントのAuth Tokenとして使用しています。マネージャー。

必要なのは、アカウントマネージャーを使用して更新トークンと認証トークンの両方を何らかの方法で保存し、アプリがAPIにアクセスしようとしてエラー応答を受け取った場合:{"error": "access token expired"}refreshToken以前に受信したAccessTokenオブジェクトからの文字列。しかし、どうすればいいのかわかりません。

オーセンティケータークラスのgetAuthTokenメソッドは、現在次のようになっています。

@Override
public Bundle getAuthToken(AccountAuthenticatorResponse accountAuthenticatorResponse, Account account,
                           String authTokenType, Bundle options) throws NetworkErrorException {
    if (!authTokenType.equals(AccountGeneral.AUTHTOKEN_TYPE_READ_ONLY) &&
            !authTokenType.equals(AccountGeneral.AUTHTOKEN_TYPE_FULL_ACCESS)) {
        final Bundle result = new Bundle();
        result.putString(AccountManager.KEY_ERROR_MESSAGE, "Invalid authTokenType");
        return result;
    }

    final AccountManager manager = AccountManager.get(context.getApplicationContext());

    String authToken = manager.peekAuthToken(account, authTokenType);

    Log.d("Discounty", TAG + " > peekAuthToken returned - " + authToken);

    if (TextUtils.isEmpty(authToken)) {
        final String password = manager.getPassword(account);
        if (password != null) {
            try {
                authToken = discountyService.getAccessToken(DiscountyService.ACCESS_GRANT_TYPE,
                        account.name, password).toBlocking().first().getAccessToken();
// =======
// Here the above discountyService.getAccessToken(...) call returns
// AccessToken object on which I call the .getAccessToken() 
// getter which returns a string.
// =======
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    if (!TextUtils.isEmpty(authToken)) {
        final Bundle result = new Bundle();
        result.putString(AccountManager.KEY_ACCOUNT_NAME, account.name);
        result.putString(AccountManager.KEY_ACCOUNT_TYPE, account.type);
        result.putString(AccountManager.KEY_AUTHTOKEN, authToken);
        return result;
    }

    final Intent intent = new Intent(context, LoginActivity.class);
    intent.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE, accountAuthenticatorResponse);
    intent.putExtra(LoginActivity.ARG_ACCOUNT_TYPE, account.type);
    intent.putExtra(LoginActivity.ARG_AUTH_TYPE, authTokenType);
    final Bundle bundle = new Bundle();
    bundle.putParcelable(AccountManager.KEY_INTENT, intent);
    return bundle;
}

クラスAccountGeneralにはいくつかの定数が含まれています。

public class AccountGeneral {

    public static final String ACCOUNT_TYPE = "com.discounty";

    public static final String ACCOUNT_NAME = "Discounty";

    public static final String AUTHTOKEN_TYPE_READ_ONLY = "Read only";

    public static final String AUTHTOKE_TYPE_READ_ONLY_LABEL = "Read only access to a Discounty account";

    public static final String AUTHTOKEN_TYPE_FULL_ACCESS = "Full access";

    public static final String AUTHTOKEN_TYPE_FULL_ACCESS_LABEL = "Full access to a Discounty account";
}

アプリもSyncAdapterを使用し、APIと頻繁にやり取りしてサーバーとの間でデータを同期します。また、これらのAPI呼び出しでは、リクエストのパラメーターとしてアクセストークンを使用する必要があるため、実際にこの更新機能を実装して自動化する必要があります。


誰かがそれを正しく実装する方法を知っていますか?


PS:ローカルデータベースを使用してすべてのデータを保存し、トークンオブジェクトも保存できます。安全ではありませんが、これは簡単なハッキングのようです。たぶん、dbレコードとして一度に1つの更新トークンだけを保存し、アプリが新しいトークンを受け取ったときにそれを更新する必要がありますか?

PPS:APIの動作方法は自由に変更できるので、APIを改善してモバイルアプリを改善するための提案があれば、それも非常に高く評価されています。

13
Denis Yakovenko

以下を使用してアカウントを最初に追加するときに、更新トークンをアカウントのユーザーデータに保存できます。

Bundle userdata = new Bundle;
userdata.putString("refreshToken", refreshToken);
mAccountManager.addAccountExplicitly (account, password, userdata);

アカウントを追加した後、次のコマンドを呼び出してユーザーデータを設定することもできます。

mAccountManager.setUserData(account, "refreshToken", refreshToken);

アクセストークンの有効期限が切れたら、次のコマンドを呼び出して更新トークンを取得できます。

String refreshToken = mAccountManager.getUserData(account, "refreshToken");

RefreshTokenを使用して、新しいアクセストークンを取得します。

6
Grace Coder