Вы можете использовать Firebase Authentication, чтобы пользователь мог войти в аккаунт, нажав на ссылку в электронном письме. В процессе также проверяется адрес электронной почты пользователя.
Вход с помощью адреса электронной почты имеет ряд преимуществ:
- Простая регистрация и вход.
- Снижается риск использования одного и того же пароля в разных приложениях, что может подорвать безопасность даже при использовании надежных паролей.
- Возможность аутентифицировать пользователя и одновременно подтвердить, что он является законным владельцем адреса электронной почты.
- Для входа в аккаунт пользователю нужен только доступ к электронной почте. Вам не нужно владеть номером телефона или аккаунтом в социальной сети.
- Пользователь может безопасно войти в аккаунт, не вводя пароль (и не запоминая его), что может быть неудобно на мобильном устройстве.
- Существующий пользователь, который ранее входил в систему с помощью идентификатора электронной почты (пароля или федеративного аккаунта), может перейти на вход только с помощью электронной почты. Например, пользователь, который забыл пароль, сможет войти в аккаунт, не сбрасывая его.
Подготовка
Если вы ещё этого не сделали, скопируйте фрагмент инициализации из Firebase в свой проект, как описано в статье Как добавить Firebase в проект JavaScript.
Как включить вход по ссылке в проекте Firebase
Чтобы пользователи могли входить в аккаунт по ссылке, отправленной на электронную почту, сначала включите поставщика "Электронная почта" и метод входа "Ссылка на электронную почту" для своего проекта Firebase:
В консоли Firebase выберите Безопасность > Аутентификация.
На вкладке Sign-in method (Способ входа) включите способ входа Email/Password (Адрес электронной почты/пароль). Обратите внимание, что для входа по ссылке необходимо включить вход с использованием адреса электронной почты и пароля.
В том же разделе включите поставщика Ссылка на электронную почту (вход без пароля).
Нажмите Сохранить.
Отправка ссылки для аутентификации на адрес электронной почты пользователя
Чтобы запустить процесс аутентификации, предложите пользователю ввести адрес электронной почты и вызовите функцию sendSignInLinkToEmail, чтобы Firebase отправил ссылку для аутентификации на указанный адрес.
Создайте объект
ActionCodeSettings, который содержит инструкции для Firebase о том, как создать ссылку в письме. Задайте следующие поля:url– ссылка на контент, которую нужно встроить, и любые дополнительные данные, которые нужно передать. Если вы ещё не добавили домен в список авторизованных доменов, сделайте это:В консоли Firebase выберите Безопасность > Аутентификация > вкладка Настройки.
В разделе Авторизованные домены нажмите Добавить домен и добавьте свой домен.
androidиiosпомогают Firebase Authentication определить, нужно ли создавать ссылку только для сайта или мобильную ссылку, которая будет открываться на устройстве Android или Apple.handleCodeInApp– задайте значение true. В отличие от других действий, выполняемых вне приложения (например, сброса пароля и подтверждения адреса электронной почты), вход в аккаунт всегда должен осуществляться в приложении. Это связано с тем, что в конце процесса пользователь должен войти в аккаунт, а состояние аутентификации должно сохраниться в приложении.linkDomain: если для проекта определены специальные домены ссылок Hosting, укажите, какой из них следует использовать, когда ссылка открывается в определенном мобильном приложении. В противном случае автоматически выбирается домен по умолчанию (например, ).PROJECT_ID.firebaseapp.comdynamicLinkDomain: поддержка прекращена. Не указывайте этот параметр.Web
const actionCodeSettings = { // URL you want to redirect back to. The domain (www.example.com) for this // URL must be in the authorized domains list in the Firebase Console. url: 'https://www.example.com/finishSignUp?cartId=1234', // This must be true. handleCodeInApp: true, iOS: { bundleId: 'com.example.ios' }, android: { packageName: 'com.example.android', installApp: true, minimumVersion: '12' }, // The domain must be configured in Firebase Hosting and owned by the project. linkDomain: 'custom-domain.com' };
Web
var actionCodeSettings = { // URL you want to redirect back to. The domain (www.example.com) for this // URL must be in the authorized domains list in the Firebase Console. url: 'https://www.example.com/finishSignUp?cartId=1234', // This must be true. handleCodeInApp: true, iOS: { bundleId: 'com.example.ios' }, android: { packageName: 'com.example.android', installApp: true, minimumVersion: '12' }, dynamicLinkDomain: 'example.page.link' };
Подробнее о параметре
ActionCodeSettingsрассказывается в разделе Передача состояния в действиях с электронной почтой.Запросите у пользователя адрес электронной почты.
Отправьте ссылку для аутентификации на адрес электронной почты пользователя и сохраните этот адрес на случай, если пользователь выполнит вход с помощью электронной почты на том же устройстве.
Web
import { getAuth, sendSignInLinkToEmail } from "firebase/auth"; const auth = getAuth(); sendSignInLinkToEmail(auth, email, actionCodeSettings) .then(() => { // The link was successfully sent. Inform the user. // Save the email locally so you don't need to ask the user for it again // if they open the link on the same device. window.localStorage.setItem('emailForSignIn', email); // ... }) .catch((error) => { const errorCode = error.code; const errorMessage = error.message; // ... });
Web
firebase.auth().sendSignInLinkToEmail(email, actionCodeSettings) .then(() => { // The link was successfully sent. Inform the user. // Save the email locally so you don't need to ask the user for it again // if they open the link on the same device. window.localStorage.setItem('emailForSignIn', email); // ... }) .catch((error) => { var errorCode = error.code; var errorMessage = error.message; // ... });
Как войти в аккаунт с помощью ссылки в письме
Проблемы с безопасностью
Чтобы предотвратить использование ссылки для входа в аккаунт не того пользователя или на не том устройстве, Firebase Auth требует, чтобы при завершении процесса входа был указан адрес электронной почты пользователя. Чтобы войти в аккаунт, необходимо указать адрес электронной почты, на который была отправлена ссылка для входа.
Вы можете упростить этот процесс для пользователей, которые открывают ссылку для входа на том же устройстве, на котором запросили ее. Для этого сохраните их адрес электронной почты локально, например с помощью localStorage или файлов cookie, когда отправляете письмо для входа. Затем используйте этот адрес, чтобы завершить процесс. Не передавайте адрес электронной почты пользователя в параметрах URL переадресации и не используйте его повторно, так как это может привести к внедрению сеанса.
После завершения входа все предыдущие непроверенные способы входа будут удалены у пользователя, а все существующие сеансы станут недействительными. Например, если кто-то ранее создал непроверенный аккаунт с тем же адресом электронной почты и паролем, пароль пользователя будет удален, чтобы предотвратить повторный вход в этот непроверенный аккаунт.
Кроме того, убедитесь, что в рабочей версии используется URL с протоколом HTTPS, чтобы избежать перехвата ссылки промежуточными серверами.
Завершение входа на веб-странице
Формат прямой ссылки в электронном письме такой же, как и формат, используемый для действий с электронной почтой вне основного процесса (подтверждение адреса электронной почты, сброс пароля и отмена изменения адреса).
Firebase Auth упрощает эту проверку, предоставляя API isSignInWithEmailLink, который позволяет определить, является ли ссылка ссылкой для входа с помощью электронной почты.
Чтобы завершить вход на целевой странице, вызовите функцию signInWithEmailLink, передав ей адрес электронной почты пользователя и ссылку на письмо с одноразовым кодом.
Web
import { getAuth, isSignInWithEmailLink, signInWithEmailLink } from "firebase/auth"; // Confirm the link is a sign-in with email link. const auth = getAuth(); if (isSignInWithEmailLink(auth, window.location.href)) { // Additional state parameters can also be passed via URL. // This can be used to continue the user's intended action before triggering // the sign-in operation. // Get the email if available. This should be available if the user completes // the flow on the same device where they started it. let email = window.localStorage.getItem('emailForSignIn'); if (!email) { // User opened the link on a different device. To prevent session fixation // attacks, ask the user to provide the associated email again. For example: email = window.prompt('Please provide your email for confirmation'); } // The client SDK will parse the code from the link for you. signInWithEmailLink(auth, email, window.location.href) .then((result) => { // Clear email from storage. window.localStorage.removeItem('emailForSignIn'); // You can access the new user by importing getAdditionalUserInfo // and calling it with result: // getAdditionalUserInfo(result) // You can access the user's profile via: // getAdditionalUserInfo(result)?.profile // You can check if the user is new or existing: // getAdditionalUserInfo(result)?.isNewUser }) .catch((error) => { // Some error occurred, you can inspect the code: error.code // Common errors could be invalid email and invalid or expired OTPs. }); }
Web
// Confirm the link is a sign-in with email link. if (firebase.auth().isSignInWithEmailLink(window.location.href)) { // Additional state parameters can also be passed via URL. // This can be used to continue the user's intended action before triggering // the sign-in operation. // Get the email if available. This should be available if the user completes // the flow on the same device where they started it. var email = window.localStorage.getItem('emailForSignIn'); if (!email) { // User opened the link on a different device. To prevent session fixation // attacks, ask the user to provide the associated email again. For example: email = window.prompt('Please provide your email for confirmation'); } // The client SDK will parse the code from the link for you. firebase.auth().signInWithEmailLink(email, window.location.href) .then((result) => { // Clear email from storage. window.localStorage.removeItem('emailForSignIn'); // You can access the new user via result.user // Additional user info profile not available via: // result.additionalUserInfo.profile == null // You can check if the user is new or existing: // result.additionalUserInfo.isNewUser }) .catch((error) => { // Some error occurred, you can inspect the code: error.code // Common errors could be invalid email and invalid or expired OTPs. }); }
Как войти в аккаунт в мобильном приложении
Firebase Authentication использует Firebase Hosting, чтобы отправить ссылку на мобильное устройство. Чтобы завершить вход через мобильное приложение, его нужно настроить так, чтобы оно обнаруживало входящую ссылку на приложение, анализировало лежащую в ее основе ссылку на контент и завершало вход так же, как при использовании веб-интерфейса.
Чтобы узнать, как реализовать вход с помощью ссылки в письме в приложении для Android, ознакомьтесь с руководством по Android.
Чтобы узнать, как реализовать вход с помощью ссылки в письме в приложении Apple, ознакомьтесь с руководством по платформам Apple.
Установка связи или повторная аутентификация с помощью ссылки в электронном письме
Вы также можете связать этот способ аутентификации с существующим пользователем. Например, пользователь, ранее прошедший аутентификацию с помощью другого поставщика, такого как номер телефона, может добавить этот способ входа в свой существующий аккаунт.
Разница будет во второй половине операции:
Web
import { getAuth, linkWithCredential, EmailAuthProvider } from "firebase/auth"; // Construct the email link credential from the current URL. const credential = EmailAuthProvider.credentialWithLink( email, window.location.href); // Link the credential to the current user. const auth = getAuth(); linkWithCredential(auth.currentUser, credential) .then((usercred) => { // The provider is now successfully linked. // The phone user can now sign in with their phone number or email. }) .catch((error) => { // Some error occurred. });
Web
// Construct the email link credential from the current URL. var credential = firebase.auth.EmailAuthProvider.credentialWithLink( email, window.location.href); // Link the credential to the current user. firebase.auth().currentUser.linkWithCredential(credential) .then((usercred) => { // The provider is now successfully linked. // The phone user can now sign in with their phone number or email. }) .catch((error) => { // Some error occurred. });
Также этот метод можно использовать для повторной аутентификации пользователя, перешедшего по ссылке в электронном письме, перед выполнением конфиденциальной операции.
Web
import { getAuth, reauthenticateWithCredential, EmailAuthProvider } from "firebase/auth"; // Construct the email link credential from the current URL. const credential = EmailAuthProvider.credentialWithLink( email, window.location.href); // Re-authenticate the user with this credential. const auth = getAuth(); reauthenticateWithCredential(auth.currentUser, credential) .then((usercred) => { // The user is now successfully re-authenticated and can execute sensitive // operations. }) .catch((error) => { // Some error occurred. });
Web
// Construct the email link credential from the current URL. var credential = firebase.auth.EmailAuthProvider.credentialWithLink( email, window.location.href); // Re-authenticate the user with this credential. firebase.auth().currentUser.reauthenticateWithCredential(credential) .then((usercred) => { // The user is now successfully re-authenticated and can execute sensitive // operations. }) .catch((error) => { // Some error occurred. });
Однако поскольку процесс может быть завершен на другом устройстве, на котором пользователь не вошел в аккаунт, он может быть не завершен. В таком случае пользователю может быть показано сообщение об ошибке, чтобы он открыл ссылку на том же устройстве. В ссылку можно добавить информацию о типе операции и идентификаторе пользователя.
Устарело: различие между адресом электронной почты и паролем и ссылкой для входа
Если вы создали проект 15 сентября 2023 г. или позже, защита от перечисления адресов электронной почты включена по умолчанию. Эта функция повышает безопасность аккаунтов пользователей проекта, но отключает метод fetchSignInMethodsForEmail(), который мы ранее рекомендовали для реализации потоков с идентификатором.
Хотя вы можете отключить защиту от перечисления адресов электронной почты для своего проекта, мы не рекомендуем этого делать.
Подробная информация приведена в документации по защите от перечисления адресов электронной почты.
Шаблон письма по умолчанию для входа по ссылке
В шаблоне письма по умолчанию в тему и текст добавляется временная метка, чтобы последующие письма не объединялись в одну цепочку и ссылка не скрывалась.
Этот шаблон можно использовать на следующих языках:
| Код | Язык |
|---|---|
| ar | Арабский |
| zh-CN | Китайский (упрощенный) |
| zh-TW | Китайский (традиционный) |
| nl | Нидерландский |
| en | Английский |
| en-GB | Английский (Великобритания) |
| fr | Французский |
| de | Немецкий |
| id | Индонезийский |
| it | Итальянский |
| ja | Японский |
| ko | Корейский |
| pl | Польский |
| pt-BR | Португальский (Бразилия) |
| pt-PT | Португальский (Португалия) |
| ru | Русский |
| es | Испанский |
| es-419 | Испанский (Латинская Америка) |
| th | Тайский |
Дальнейшие действия
После первого входа пользователя создается новый аккаунт, связанный с учетными данными, которые он использовал (именем пользователя и паролем, номером телефона или информацией поставщика услуг аутентификации). Этот новый аккаунт хранится в проекте Firebase и позволяет идентифицировать пользователя во всех приложениях проекта независимо от того, как он вошел в аккаунт.
-
В приложениях рекомендуется отслеживать статус аутентификации пользователя, установив наблюдатель для объекта
Auth. Затем вы можете получить основную информацию о профиле пользователя из объектаUser. Подробнее о том, как управлять пользователями… В Firebase Realtime Database и Cloud Storage правилах безопасности можно получить уникальный идентификатор пользователя, выполнившего вход, из переменной
authи использовать его, чтобы контролировать, к каким данным у пользователя есть доступ.
Вы можете разрешить пользователям входить в ваше приложение, используя несколько поставщиков услуг аутентификации, связав учетные данные поставщика услуг аутентификации с существующим аккаунтом пользователя.
Чтобы выйти из аккаунта пользователя, вызовите функцию
signOut:
Web
import { getAuth, signOut } from "firebase/auth"; const auth = getAuth(); signOut(auth).then(() => { // Sign-out successful. }).catch((error) => { // An error happened. });
Web
firebase.auth().signOut().then(() => { // Sign-out successful. }).catch((error) => { // An error happened. });