web-dev-qa-db-fra.com

Connectez-vous à votre compte Google avec un ancien mot de passe - comment rediriger vers la page bleue de connexion à Google?

J'ai implémenté le SDK de connexion Google dans mon application et cela fonctionne très bien. Lorsque je clique sur le bouton de connexion, une fenêtre s'ouvre affichant les comptes déjà stockés. La sélection de l'un de ces comptes met fin au processus de connexion.

Le seul cas d'utilisation qui ne réussit pas est lorsque l'utilisateur accède à la boîte de dialogue de connexion et clique sur un compte qui a un mot de passe non valide. Je ne sais pas comment résoudre ce problème.


J'ai suivi avec l'instruction Google "implémenter le SDK de connexion" et après avoir appelé ces lignes:

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

J'attrape une exception avec le code d'état 12501 SIGN_IN_CANCELLED.

Comme je l'ai déjà dit, cela se produit car l'un des comptes stockés a un mot de passe invalide.

Voici les étapes pour reproduire:

  1. l'utilisateur s'est connecté une fois
  2. boîte de dialogue stocké ses informations d'identification
  3. pendant ce temps, l'utilisateur a changé le mot de passe de son compte sur www
  4. l'utilisateur sélectionne les informations d'identification enregistrées
  5. un code d'erreur non lié se produit).

Comment puis-je inciter l'utilisateur à rediriger vers cette page de connexion Google bleue et à conserver le flux actuel?

Par exemple, AliExpress peut gérer cela et redirige l'utilisateur vers la page bleue en demandant à l'utilisateur de se reconnecter.

enter image description here

Mon code n'est pas très différent de celui des instructions de Google. Ceci est mon flux de code. Tout commence par onClick():

Dans la méthode 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);

Dans la section 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

Avis de non-responsabilité Je ne suis pas un employé de Google. Tout ce que je dis ci-dessous est mes conclusions d'enquêter sur des questions similaires.

Réponse courte

Vous faites tout bien. C'est le moyen recommandé de se connecter au compte Google. Malheureusement, il n'y a pas de rappel réel dans ce mécanisme pour spécifier ce qui s'est réellement passé dans votre cas. La façon dont Google Play Services le gère consiste à informer l'utilisateur que ses informations d'identification sont devenues obsolètes par notification que vous pouvez voir ci-dessous (juste après le changement de mot de passe).

notification

Je recommanderais de déposer un bug pour ajouter des codes de résultat supplémentaires pour votre cas sur https://issuetracker.google.com car cela semble être une amélioration sensible.

Réponse longue

Google utilise API de compte Android comme tout le monde (vous pouvez l'essayer vous-même). Dans les coulisses, c'est juste un mécanisme de récupération et de stockage de jetons oauth.

Lorsque le mot de passe a été modifié, le jeton n'est plus valide et vous obtenez des erreurs en essayant de l'utiliser.

La façon dont cela fonctionne est la façon dont les développeurs des services Google Play ont choisi de l'implémenter (c'est pourquoi je vous recommande de déposer un bogue).

Par exemple, AliExpress peut gérer cela et redirige l'utilisateur vers la page bleue en demandant à l'utilisateur de se reconnecter.

Aliexpress utilise le API obsolète . Comme vous pouvez le voir, la boîte de dialogue de sélection du compte a une couleur différente et pas d'avatars. L'API est toujours utilisable, mais peut être arrêtée à tout moment (ou non). Je ne vous recommande pas de l'utiliser, mais voici comment cela fonctionne:

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

    }
}

J'espère que ça aide!

[~ # ~] upd [~ # ~] : les nouvelles API Google Play ont ResolvableApiException , ce qui étend ApiException que vous attrapez . Il a la méthode startResolutionForResult () similaire à celle utilisée dans les anciennes API. Mais le Bundle que vous recevez ne contient aucune information de résolution.

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

Si vous déposez un bug, postez-le ici, nous le mettrons en vedette)

Vous pouvez également afficher la boîte de dialogue "Choisir un compte" en utilisant par défaut Android API (min API 23)

Le code ci-dessous peut être poursuivi pour afficher une "boîte de dialogue de choix de compte" en utilisant par défaut Android API de gestion de compte . Ceci est nouveau et (espérons-le) ne sera pas déconseillé pour quelque temps.

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

Vous pouvez également obtenir la liste des comptes Google, visible par votre application

Le compte devient visible pour votre application après que l'utilisateur a essayé de se connecter avec ce type de compte dans votre application, en utilisant l'une des méthodes ci-dessus. Événement si la connexion n'a pas réussi (par exemple, le mot de passe a expiré), vous verrez ce compte dans la liste (vous ne pourrez pas distinguer lequel en cas de comptes multiples). Cela peut donc être utilisé comme solution de contournement, mais de manière limitée.

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

Conclusion Malheureusement, je n'ai trouvé aucun autre moyen d'accéder aux données de compte Google pour contourner votre cas en utilisant les API de connexion Google modernes. Toutes les API AccountManager avancées nécessitent que vous ayez la même signature que l'application propriétaire du compte (GMS - Google Mobile Services), ce qui n'est pas le cas. Nous ne pouvons donc que demander cela à Google et espérons qu'il sera mis en œuvre :(

5
Amaksoft