web-dev-qa-db-ja.com

古いパスワードでGoogleアカウントにサインイン-青いGoogleサインインページにリダイレクトする方法

アプリケーションにGoogleサインインSDKを実装しましたが、正常に動作します。サインインボタンをクリックすると、既に保存されているアカウントを表示するウィンドウが開きます。これらのアカウントの1つを選択すると、サインインプロセスが正常に終了します。

成功しない1つの使用例は、ユーザーがサインインダイアログにアクセスして、無効なパスワードを持つアカウントをクリックした場合です。この問題の解決方法がわかりません。


私はGoogleの「サインインSDKの実装」の指示に従い、次の行を呼び出した後、

_Task<GoogleSignInAccount> task = GoogleSignIn.getSignedInAccountFromIntent(data);
GoogleSignInAccount googleSignInAccount = task.getResult(ApiException.class);
_

ステータスコード12501 _SIGN_IN_CANCELLED_で例外をキャッチします。

前に述べたように、これは、保存されたアカウントの1つに無効なパスワードがあるために発生します。

再現する手順は次のとおりです。

  1. ユーザーが一度ログインした
  2. ダイアログは彼の資格情報を保存しました
  3. 一方、ユーザーはwwwで自分のアカウントのパスワードを変更しました
  4. ユーザーが保存された資格情報を選択する
  5. 無関係のエラーコードが発生します)。

ユーザーにこの青いGoogleサインインページにリダイレクトさせ、現在のフローを維持するにはどうすればよいですか?

たとえば、AliExpressはどういうわけかこれを処理でき、ユーザーに再度サインインするように求めて、ユーザーをブルーページにリダイレクトします。

enter image description here

私のコードは、Googleの指示と大差ありません。これは私のコードフローです。すべてはonClick()から始まります:

onClick()メソッド内:

_// Logout before all operations
GoogleSignInAccount account = GoogleSignIn.getLastSignedInAccount(this);
if (account != null) {
    mGoogleSignInClient.signOut();
}

// Call to sign in
Intent signInIntent = mGoogleSignInClient.getSignInIntent();
startActivityForResult(signInIntent, RequestCodes.RC_GOOGLE_SIGN_IN);
_

onActivityResultセクション:

_@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    Log.d(TAG, "onActivityResult() called with: requestCode = [" + requestCode + "], resultCode = [" + resultCode + "], data = [" + data + "]");

    if (requestCode == RequestCodes.RC_GOOGLE_SIGN_IN) {

        try {

            // Call to take account data
            Task<GoogleSignInAccount> task = GoogleSignIn.getSignedInAccountFromIntent(data);

            // Fetch account data
            GoogleSignInAccount googleSignInAccount = task.getResult(ApiException.class);

            Account account = googleSignInAccount.getAccount();

            // Calling to get short lived token
            String shortLivedToken = GoogleAuthUtil.getToken(mContext, account, "oauth2:" + Scopes.PROFILE + " " + Scopes.EMAIL);

            // Further calls here...

        } catch (ApiException e) {

            //https://developers.google.com/Android/reference/com/google/Android/gms/auth/api/signin/GoogleSignInStatusCodes

            if (e.getStatusCode() == 12501) {
                Log.e(TAG, "SIGN_IN_CANCELLED");
            } else if (e.getStatusCode() == 12502) {
                Log.e(TAG, "SIGN_IN_CURRENTLY_IN_PROGRESS");
            } else if (e.getStatusCode() == 12500) {
                Log.e(TAG, "SIGN_IN_FAILED");
            } else {
                e.printStackTrace();
            }

        } catch (GoogleAuthException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

    } else {
        super.onActivityResult(requestCode, resultCode, data);
    }
}
_
24
deadfish

免責事項私はGoogleの従業員ではありません。以下に述べるすべては、同様の問題を調査した結果です。

短い答え

あなたはすべてを正しく行っています。これは、Googleアカウントへのログインに推奨される方法です。残念ながら、このメカニズムには、実際の問題を特定するための実際のコールバックはありません。 Google Play開発者サービスがこれを処理する方法は、以下に表示される通知(パスワードが変更された直後)によって資格情報が古くなったことをユーザーに通知することです。

notification

https://issuetracker.google.com でケースに結果コードを追加するためのバグを報告することをお勧めします。

長い答え

Googleは AndroidアカウントAPI を使用しています(他の人と同じです(自分で試すことができます)。舞台裏では単なるoauthトークンの取得と保存のメカニズムです。

パスワードが変更された場合、トークンは無効になり、使用しようとするとエラーが発生します。

これが機能する方法は、Google Play Services開発者が実装することを選択した方法です(したがって、バグを報告することをお勧めします)。

たとえば、AliExpressはどういうわけかこれを処理でき、ユーザーに再度サインインするように求めて、ユーザーをブルーページにリダイレクトします。

Aliexpressは 非推奨のAPI を使用しています。ご覧のとおり、アカウントを選択するためのダイアログの色は異なり、アバターはありません。 APIはまだ使用可能ですが、いつでも(またはそうでなく)シャットダウンされる可能性があります。これを使用することはお勧めしませんが、次のように機能します。

import com.google.Android.gms.common.AccountPicker;
import com.google.Android.gms.auth.GoogleAuthUtil;
import com.google.Android.gms.auth.UserRecoverableAuthException;

void chooseAccount() {
    Intent signInIntent = AccountPicker.newChooseAccountIntent(null, null, new String[]{GoogleAuthUtil.GOOGLE_ACCOUNT_TYPE}, true, null, null, null, null);
    startActivityForResult(signInIntent, REQ_CHOOSE_ACCOUNT);
}

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {

    if (requestCode == REQ_CHOOSE_ACCOUNT) {

        String email = data.getExtras().getString("authAccount");
        // better do this in background thread
        try {
            GoogleAuthUtil.getToken(this, new Account(email, GoogleAuthUtil.GOOGLE_ACCOUNT_TYPE), "oauth2:https://www.googleapis.com/auth/userinfo.profile");
        } catch (UserRecoverableAuthException recEx) {
            Intent recoverIntent = recEx.getIntent();
            // Will redirect to login activity
            startActivityForResult(recoverIntent, REQ_RECOVER);
        } catch (Exception e) {
            Log.d(TAG, "caught exception", e);
        }

    }
}

それが役に立てば幸い!

[〜#〜] upd [〜#〜]:新しいGoogle Play APIには ResolvableApiException があり、キャッチしているApiExceptionを拡張します。以前のAPIで使用されていたのと同様のメソッドstartResolutionForResult()があります。ただし、受け取るバンドルには解決情報が含まれていません。

Bundle[{googleSignInStatus=Status{statusCode=unknown status code: 12501, resolution=null}}]

バグを報告する場合は、ここに投稿してください。スターを付けます)

デフォルトのAndroid API(最小API 23))を使用して[アカウントの選択]ダイアログを表示することもできます

以下のコードは、 default Android Account Management APIs を使用して「アカウントの選択」ダイアログを表示するために訴えられる可能性があります。これは新しいものであり、(うまくいけば)しばらく。

import Android.accounts.Account;
import Android.accounts.AccountManager;

// Unfortunately can be used only on API 23 and higher
Intent signInIntent = AccountManager.newChooseAccountIntent(
            null,
            null,
            new String[] { "com.google" },
            "Please select your account",
            null,
            null,
            new Bundle());

startActivityForResult(signInIntent, REQ_SELECT_ACCOUNT);

@Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (requestCode == REQ_SELECT_ACCOUNT) {
            String accountName = data.getExtras().getString(AccountManager.KEY_ACCOUNT_NAME);
            String accountType = data.getExtras().getString(AccountManager.KEY_ACCOUNT_TYPE);
            // now you can call GoogleAuthUtil as in example above
        }
    }

Googleアカウントのリストを取得して、アプリに表示することもできます

上記のいずれかの方法を使用して、ユーザーがそのようなアカウントでアプリにサインインしようとすると、アカウントがアプリに表示されます。 サインインが失敗した場合のイベント(例:パスワードの有効期限が切れている)、リストにこのアカウントが表示されます(されませんただし、複数のアカウントの場合はどれを区別できるか)。したがって、これは回避策として使用できますが、限られた方法で使用できます。

import Android.accounts.Account;
import Android.accounts.AccountManager;

try {
        // requires Android.permission.GET_ACCOUNTS
        Account[] accounts = AccountManager.get(this).getAccountsByType("com.google");
        for (Account account : accounts) {
            Log.d(TAG, "account: " + account.name);
        }
    } catch (Exception e) {
        Log.i("Exception", "Exception:" + e);
    }

結論残念ながら、最新のGoogleサインインAPIを使用してケースを回避するためにGoogleアカウントデータにアクセスする方法は他に見つかりませんでした。すべての高度なAccountManager APIには、アカウント所有者アプリ(GMS-Googleモバイルサービス)と同じ署名が必要ですが、そうではありません。したがって、これはGoogleにのみリクエストでき、実装されることを望みます:(

5
Amaksoft