Привязка аккаунта к Google Sign-In

Вход в Google для Ассистента предоставляет пользователям и разработчикам самый простой и удобный интерфейс как для связывания учетных записей, так и для их создания. Ваше действие может запросить доступ к профилю Google вашего пользователя во время разговора, включая имя пользователя, адрес электронной почты и изображение профиля.

Информация профиля может использоваться для создания персонализированного пользовательского опыта в вашем действии. Если у вас есть приложения на других платформах и они используют вход в Google, вы также можете найти существующую учетную запись пользователя и связать ее с ней, создать новую учетную запись и установить прямой канал связи с пользователем.

Чтобы выполнить привязку учетной записи с помощью входа в Google, вы просите пользователя дать согласие на доступ к его профилю Google. Затем вы используете информацию в их профиле, например адрес электронной почты, для идентификации пользователя в вашей системе.

Реализация привязки учетной записи для входа в Google

Выполните действия, описанные в следующих разделах, чтобы добавить ссылку на учетную запись Google для входа в действие.

Настроить проект

Чтобы настроить свой проект для использования привязки учетной записи для входа в Google, выполните следующие действия:

  1. Откройте консоль действий и выберите проект.
  2. Откройте вкладку «Разработка» и выберите «Связывание учетной записи» .
  3. Включите переключатель рядом с пунктом «Привязка учетной записи» .
  4. В разделе Создание учетной записи выберите Да .
  5. В поле «Тип связи» выберите «Войти в Google» .

  6. Откройте «Информацию о клиенте» и обратите внимание на значение идентификатора клиента, присвоенного Google вашим действиям .

  7. Нажмите Сохранить .

Разработайте голосовой пользовательский интерфейс для процесса аутентификации.

Проверьте, подтвержден ли пользователь, и запустите процесс привязки учетной записи.

  1. Откройте проект Actions Builder в консоли Actions .
  2. Создайте новую сцену, чтобы начать привязку учетной записи в своем действии:
    1. Нажмите «Сцены» .
    2. Нажмите значок добавления (+), чтобы добавить новую сцену.
  3. Во вновь созданной сцене щелкните значок « для «Условия» .
  4. Добавьте условие, которое проверяет, является ли пользователь, связанный с беседой, проверенным пользователем. Если проверка не пройдена, ваше действие не сможет выполнить привязку учетной записи во время разговора и должно вернуться к предоставлению доступа к функциям, которые не требуют привязки учетной записи.
    1. В поле Enter new expression в разделе «Условие» введите следующую логику: user.verificationStatus != "VERIFIED"
    2. В разделе «Переход» выберите сцену, которая не требует привязки учетной записи, или сцену, которая является точкой входа в функции, доступные только для гостей.

  1. Нажмите значок « для «Условия» .
  2. Добавьте условие для запуска процесса связывания учетной записи, если у пользователя нет связанного удостоверения.
    1. В поле Enter new expression в разделе « Условие» введите следующую логику: user.verificationStatus == "VERIFIED"
    2. В разделе «Переход» выберите системную сцену «Связывание учетных записей» .
    3. Нажмите Сохранить .

После сохранения в ваш проект добавляется новая сцена системы связывания учетных записей под названием <SceneName>_AccountLinking .

Настройте сцену привязки учетной записи

  1. В разделе «Сцены» выберите сцену системы привязки учетной записи.
  2. Нажмите « Отправить запрос» и добавьте короткое предложение, описывающее пользователю, почему Действию необходим доступ к его личности (например, «Чтобы сохранить ваши настройки»).
  3. Нажмите Сохранить .

  1. В разделе «Условия» нажмите «Если пользователь успешно завершил привязку учетной записи» .
  2. Настройте, как должен действовать поток, если пользователь соглашается связать свою учетную запись. Например, вызовите веб-перехватчик для обработки любой необходимой пользовательской бизнес-логики и возврата к исходной сцене.
  3. Нажмите Сохранить .

  1. В разделе «Условия» выберите «Если пользователь отменяет или отклоняет привязку учетной записи» .
  2. Настройте порядок действий, если пользователь не согласен связать свою учетную запись. Например, отправьте подтверждающее сообщение и перенаправьте на сцены, которые предоставляют функциональные возможности, не требующие привязки учетной записи.
  3. Нажмите Сохранить .

  1. В разделе «Условия» выберите «При возникновении системной или сетевой ошибки» .
  2. Настройте, как должен действовать процесс, если процесс связывания учетных записей не может быть завершен из-за системных или сетевых ошибок. Например, отправьте подтверждающее сообщение и перенаправьте на сцены, которые предоставляют функциональные возможности, не требующие привязки учетной записи.
  3. Нажмите Сохранить .

Доступ к информации профиля в вашем бэкэнде

После того как пользователь разрешит ваше действие для доступа к своему профилю Google, вы получите токен Google ID, который будет содержать информацию о профиле Google пользователя в каждом последующем запросе вашего действия.

Чтобы получить доступ к информации профиля пользователя, вам необходимо сначала проверить и декодировать токен, выполнив следующие действия:

  1. Используйте библиотеку декодирования JWT для вашего языка для декодирования токена и используйте открытые ключи Google (доступные в формате JWK или PEM ) для проверки подписи токена.
  2. Убедитесь, что эмитент токена (поле iss в декодированном токене) — https://accounts.google.com , а аудитория (поле aud в декодированном токене) — это значение идентификатора клиента, выданного Google для ваших действий , то есть назначенный вашему проекту в консоли действий.

Ниже приведен пример декодированного токена:

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

Если вы используете библиотеку Actions on Google Fulfillment для Node.js , она позаботится о проверке и декодировании токена за вас и предоставит вам доступ к содержимому профиля, как показано в следующих фрагментах кода.

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

Обработка запросов на доступ к данным

Чтобы обработать запрос на доступ к данным, просто убедитесь, что пользователь, подтвержденный токеном идентификатора Google, уже присутствует в вашей базе данных. В следующем фрагменте кода показан пример того, как проверить, существуют ли уже заказы для пользователя в базе данных 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!');
});