Associer des comptes avec Google Sign-In

Google Sign-In pour l'Assistant offre aux utilisateurs et aux développeurs l'expérience la plus simple et la plus simple possible pour l'association et la création de comptes. Au cours d'une conversation, votre action peut demander l'accès au profil Google de l'utilisateur, y compris son nom, son adresse e-mail et sa photo de profil.

Les informations de profil peuvent être utilisées pour créer une expérience utilisateur personnalisée dans votre action. Si vous avez des applications sur d'autres plates-formes et qu'elles utilisent Google Sign-In, vous pouvez également rechercher le compte d'un utilisateur existant et l'associer, en créer un et établir un canal de communication direct avec l'utilisateur.

Pour associer un compte avec Google Sign-In, vous devez demander à l'utilisateur d'autoriser l'accès à son profil Google. Vous pouvez ensuite identifier l'utilisateur dans votre système à l'aide des informations de son profil (son adresse e-mail, par exemple).

Implémenter l'association de compte Google Sign-In

Suivez les étapes des sections suivantes pour ajouter un compte Google Sign-In associé à votre action.

Configurer le projet

Pour configurer votre projet afin d'utiliser l'association de compte Google Sign-In, procédez comme suit:

  1. Ouvrez la console Actions et sélectionnez un projet.
  2. Cliquez sur l'onglet Développer, puis sélectionnez Association de comptes.
  3. Activez le bouton bascule à côté de Association de comptes.
  4. Dans la section Création du compte, sélectionnez Oui.
  5. Dans Type d'association, sélectionnez Google Sign-In.

  6. Ouvrez la section Informations sur le client et notez la valeur de l'ID client attribué par Google à vos actions.

  7. Cliquez sur Enregistrer.

Concevoir l'interface utilisateur vocale pour le flux d'authentification

Vérifier si l'utilisateur est validé et démarrer le flux d'association de compte

  1. Ouvrez votre projet Actions Builder dans la console Actions.
  2. Créez une scène pour lancer l'association de comptes dans votre action :
    1. Cliquez sur Scenes (Scènes).
    2. Cliquez sur l'icône d'ajout (+) pour ajouter une scène.
  3. Dans la scène que vous venez de créer, cliquez sur l'icône d'ajout pour Conditions.
  4. Ajoutez une condition qui vérifie si l'utilisateur associé à la conversation est un utilisateur validé. Si la vérification échoue, votre action ne peut pas associer de compte pendant la conversation. Elle doit alors fournir l'accès à des fonctionnalités qui ne nécessitent pas d'association de compte.
    1. Dans le champ Enter new expression, sous Condition, saisissez la logique suivante : user.verificationStatus != "VERIFIED"
    2. Sous Transition, sélectionnez une scène ne nécessitant pas d'association de compte ou une scène qui est le point d'entrée de la fonctionnalité Invité.

  1. Cliquez sur l'icône d'ajout pour Conditions.
  2. Ajoutez une condition pour déclencher un flux d'association de compte si l'utilisateur n'est associé à aucune identité.
    1. Dans le champ Enter new expression, sous Condition, saisissez la logique suivante : user.verificationStatus == "VERIFIED"
    2. Sous Transition, sélectionnez la scène système Association de comptes.
    3. Cliquez sur Enregistrer.

Après l'enregistrement, une nouvelle scène système d'association de comptes appelée <SceneName>_AccountLinking est ajoutée à votre projet.

Personnaliser la scène de l'association de comptes

  1. Sous Scenes (Scènes), sélectionnez la scène du système d'association de comptes.
  2. Cliquez sur Envoyer une invite et ajoutez une courte phrase pour expliquer à l'utilisateur pourquoi l'action doit accéder à son identité (par exemple, "Enregistrer vos préférences").
  3. Cliquez sur Enregistrer.

  1. Sous Conditions, cliquez sur Si l'utilisateur a correctement associé ses comptes.
  2. Configurez le déroulement du flux si l'utilisateur accepte d'associer son compte. Par exemple, appelez le webhook pour traiter toute logique métier personnalisée requise et revenir à la scène d'origine.
  3. Cliquez sur Enregistrer.

  1. Sous Conditions, cliquez sur Si l'utilisateur annule ou ignore l'association de comptes.
  2. Configurez le déroulement du flux si l'utilisateur n'accepte pas d'associer son compte. Par exemple, envoyez un message de confirmation et redirigez vers des scènes qui fournissent des fonctionnalités qui ne nécessitent pas d'association de compte.
  3. Cliquez sur Enregistrer.

  1. Sous Conditions, cliquez sur Si une erreur système ou réseau se produit.
  2. Configurez la manière dont le flux doit se dérouler si le flux d'association de comptes ne peut pas être terminé en raison d'erreurs système ou réseau. Par exemple, envoyez un message de confirmation et redirigez vers des scènes qui fournissent des fonctionnalités qui ne nécessitent pas d'association de compte.
  3. Cliquez sur Enregistrer.

Accéder aux informations de profil dans le backend

Une fois que l'utilisateur a autorisé votre action à accéder à son profil Google, vous recevez un jeton d'ID Google contenant les informations de son profil Google dans chaque requête ultérieure envoyée à votre action.

Pour accéder aux informations de profil de l'utilisateur, vous devez d'abord valider et décoder le jeton en procédant comme suit:

  1. Décodez le jeton à l'aide d'une bibliothèque de décodage JWT correspondant à votre langage, puis vérifiez la signature du jeton à l'aide des clés publiques Google (disponibles au format JWK ou PEM).
  2. Vérifiez que l'émetteur du jeton (champ iss dans le jeton décodé) est https://accounts.google.com et que l'audience (champ aud du jeton décodé) correspond à la valeur de l'ID client émis par Google pour vos actions, qui est attribué à votre projet dans la console Actions.

Voici un exemple de jeton décodé:

{
  "sub": 1234567890,        // The unique ID of the user's Google Account
  "iss": "https://accounts.google.com",        // The token's issuer
  "aud": "123-abc.apps.googleusercontent.com", // Client ID assigned to your Actions project
  "iat": 233366400,         // Unix timestamp of the token's creation time
  "exp": 233370000,         // Unix timestamp of the token's expiration time
  "name": "Jan Jansen",
  "given_name": "Jan",
  "family_name": "Jansen",
  "email": "jan@gmail.com", // If present, the user's email address
  "locale": "en_US"
}

Si vous utilisez la bibliothèque de traitement Actions on Google pour Node.js, elle se charge de valider et de décoder le jeton à votre place, et vous donne accès au contenu du profil, comme indiqué dans les extraits de code suivants.

...
const app = conversation({
  // REPLACE THE PLACEHOLDER WITH THE CLIENT_ID OF YOUR ACTIONS PROJECT
  clientId: CLIENT_ID,
});
...
// Invoked on successful completion of account linking flow, check if we need to
// create a Firebase user.
app.handle('linkAccount', async conv => {
  let payload = conv.headers.authorization;
  if (payload) {
  // Get UID for Firebase auth user using the email of the user
    const email = payload.email;
    if (!conv.user.params.uid && email) {
      try {
        conv.user.params.uid = (await auth.getUserByEmail(email)).uid;
      } catch (e) {
        if (e.code !== 'auth/user-not-found') {
          throw e;
        }
        // If the user is not found, create a new Firebase auth user
        // using the email obtained from Google Assistant
        conv.user.params.uid = (await auth.createUser({email})).uid;
      }
    }
  }
});

Gérer les demandes d'accès aux données

Pour gérer la demande d'accès aux données, vérifiez simplement que l'utilisateur revendiqué par le jeton d'ID Google est déjà présent dans votre base de données. L'extrait de code suivant montre comment vérifier si les commandes d'un utilisateur existent déjà dans une base de données Firestore:

...
app.handle('Place_Order', async conv => {
  const order = conv.session.params.order;
  const userDoc = dbs.user.doc(conv.user.params.uid);
  const orderHistory = userDoc.collection("orderHistory");
  if (orderHistory) {
    // Order history exists, so the user already placed an order.
    // Update counter for order type.
    await orderHistory.doc(order).update({ count: admin.firestore.FieldValue.increment(1)});
  } else {
    // First order they place
    await orderHistory.doc(order).set({ option: order, count: 1});
    options.forEach(opt => {
      if (opt != order) {
        orderHistory.doc(opt).set({ option: opt, count: 0});
      }
    });
  }
  return conv.add(`Your ${order} has been placed. ` +
      'Thanks for using Boba Bonanza, see you soon!');
});