Рекомендации по использованию signInWithRedirect в браузерах, блокирующих доступ к стороннему хранилищу

В этом документе описаны рекомендации по использованию входа с переадресацией в браузерах, которые блокируют сторонние файлы cookie. Чтобы signInWithRedirect() работал в производственной среде во всех браузерах, необходимо выполнить одно из указанных ниже действий.

Обзор

Чтобы сделать процесс signInWithRedirect() удобным для вас и ваших пользователей, Firebase Authentication JavaScript SDK использует междоменный iframe, который подключается к домену Firebase Hosting вашего приложения. Однако этот механизм не работает с браузерами, которые блокируют доступ к стороннему хранилищу.

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

  • Если вы размещаете приложение с помощью Firebase Hosting на субдомене firebaseapp.com, эта проблема вас не затронет и никаких действий предпринимать не нужно.
  • Если вы размещаете приложение с помощью Firebase Hosting на собственном домене или субдомене web.app, используйте вариант 1.
  • Если вы разместили приложение не в Firebase, используйте вариант 2, вариант 3, вариант 4 или вариант 5.

Вариант 1. Измените конфигурацию Firebase, чтобы использовать собственный домен в качестве authDomain

Если вы размещаете приложение на Firebase Hosting, используя собственный домен, вы можете настроить Firebase SDK так, чтобы он использовал ваш домен в качестве authDomain. Это гарантирует, что приложение и окно iframe авторизации используют один и тот же домен, что предотвращает проблему входа. Если вы не используете Firebase Hosting, вам потребуется другой вариант. Убедитесь, что пользовательский домен настроен в том же проекте, который вы используете для аутентификации.

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

  1. Настройте Firebase JS SDK так, чтобы в качестве authDomain использовался ваш пользовательский домен:

    const firebaseConfig = {
      apiKey: "<api-key>",
      authDomain: "<the-domain-that-serves-your-app>",
      databaseURL: "<database-url>",
      projectId: "<project-id>",
      appId: "<app-id>"
    };
    
  1. Добавьте новый URI перенаправления authDomain в список авторизованных URI перенаправления поставщика OAuth. Инструкции зависят от поставщика, но в целом вы можете следовать указаниям из раздела "Перед началом работы" в любом руководстве по настройке поставщика (например, Facebook). Обновленный URI для авторизации выглядит так: https://<the-domain-that-serves-your-app>/__/auth/handler. Обратите внимание на символ /__/auth/handler в конце.

    Если вы используете поставщика SAML, добавьте новый параметр authDomain в URL сервиса Assertion Consumer Service (ACS) SAML.

  2. Убедитесь, что ваш continue_uri есть в списке авторизованных доменов.

  3. При необходимости повторно разверните Firebase Hosting, чтобы получить самый свежий файл конфигурации Firebase, размещенный по адресу /__/firebase/init.json.

Вариант 2. Переключитесь на signInWithPopup()

Используйте signInWithPopup() вместо signInWithRedirect(). Остальная часть кода приложения остается прежней, но объект UserCredential извлекается по-другому.

Web

  // Before
  // ==============
  signInWithRedirect(auth, new GoogleAuthProvider());
  // After the page redirects back
  const userCred = await getRedirectResult(auth);

  // After
  // ==============
  const userCred = await signInWithPopup(auth, new GoogleAuthProvider());

Web

  // Before
  // ==============
  firebase.auth().signInWithRedirect(new firebase.auth.GoogleAuthProvider());
  // After the page redirects back
  var userCred = await firebase.auth().getRedirectResult();

  // After
  // ==============
  var userCred = await firebase.auth().signInWithPopup(
      new firebase.auth.GoogleAuthProvider());
```

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

Вариант 3. Перенаправление запросов аутентификации на firebaseapp.com

Поток signInWithRedirect начинается с перенаправления из домена вашего приложения в домен, указанный в параметре authDomain в конфигурации Firebase (по умолчанию ".firebaseapp.com"). authDomain содержит код помощника по входу, который перенаправляет пользователя к поставщику идентификационной информации, а тот, в свою очередь, – обратно в домен приложения.

Когда поток аутентификации возвращается в домен вашего приложения, осуществляется доступ к локальному хранилищу браузера вспомогательного домена для входа. Этот вариант и следующий (самостоятельное размещение кода) устраняют доступ к хранилищу с разных источников, который в противном случае блокируется браузерами.

  1. Настройте обратный прокси-сервер на сервере приложения, чтобы запросы GET/POST к https://<app domain>/__/auth/ перенаправлялись на https://<project>.firebaseapp.com/__/auth/. Переадресация должна быть прозрачной для браузера. Ее нельзя выполнять с помощью переадресации 302.

    Если вы используете nginx для обслуживания собственного домена, конфигурация обратного прокси-сервера будет выглядеть следующим образом:

    # reverse proxy for signin-helpers for popup/redirect sign in.
    location /__/auth {
      proxy_pass https://<project>.firebaseapp.com;
    }
    
  2. Следуйте инструкциям в варианте 1, чтобы обновить авторизованный redirect_uri, URL ACS и authDomain. После повторного развертывания приложения доступ к хранилищу с разных источников должен прекратиться.

Вариант 4. Разместите код помощника по входу в свой домен

Ещё один способ устранить доступ к хранилищу с разных источников – разместить код помощника по входу Firebase на собственном хостинге. Однако этот подход не работает для входа через Apple или SAML. Используйте этот вариант, только если настройка обратного прокси-сервера, описанная в варианте 3, невозможна.

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

  1. Скачайте файлы на хост из местоположения <project>.firebaseapp.com, выполнив следующие команды:

    mkdir signin_helpers/ && cd signin_helpers
    wget https://<project>.firebaseapp.com/__/auth/handler
    wget https://<project>.firebaseapp.com/__/auth/handler.js
    wget https://<project>.firebaseapp.com/__/auth/experiments.js
    wget https://<project>.firebaseapp.com/__/auth/iframe
    wget https://<project>.firebaseapp.com/__/auth/iframe.js
    wget https://<project>.firebaseapp.com/__/auth/links
    wget https://<project>.firebaseapp.com/__/auth/links.js
    wget https://<project>.firebaseapp.com/__/firebase/init.json
    
  2. Разместите указанные выше файлы в домене приложения. Убедитесь, что ваш веб-сервер может отвечать на запросы к https://<app domain>/__/auth/<filename> и https://<app domain>/__/firebase/init.json.

    Ниже приведен пример реализации сервера, который скачивает и размещает файлы. Рекомендуем периодически скачивать и синхронизировать файлы, чтобы получать последние исправления ошибок и новые функции.

  3. Выполните инструкции из раздела Вариант 1, чтобы обновить авторизованный файл redirect_uri и файл authDomain. После повторного развертывания приложения доступ к хранилищу с разных источников должен прекратиться.

Вариант 5. Обрабатывайте вход через поставщика услуг независимо

В Firebase Authentication SDK есть удобные методы signInWithPopup() и signInWithRedirect(), которые позволяют реализовать сложную логику без использования другого SDK. Вы можете вообще не использовать ни один из этих методов, если сначала самостоятельно войдете в аккаунт поставщика, а затем с помощью signInWithCredential() обменяете учетные данные поставщика на учетные данные Firebase Authentication. Например, вы можете использовать Google Sign In SDK и пример кода, чтобы получить учетные данные аккаунта Google, а затем создать новые учетные данные Google, выполнив следующий код:

Web

  // `googleUser` from the onsuccess Google Sign In callback.
  //  googUser = gapi.auth2.getAuthInstance().currentUser.get();
  const credential = GoogleAuthProvider.credential(googleUser.getAuthResponse().id_token);
  const result = await signInWithCredential(auth, credential);

Web

  // `googleUser` from the onsuccess Google Sign In callback.
  const credential = firebase.auth.GoogleAuthProvider.credential(
      googleUser.getAuthResponse().id_token);
  const result = await firebase.auth().signInWithCredential(credential);

После вызова signInWithCredential() приложение будет работать так же, как и раньше.

Инструкции по получению учетных данных Apple приведены здесь.