Uwierzytelnianie w Firebase za pomocą linku e-mail w JavaScript

Możesz użyć uwierzytelniania Firebase, aby zalogować użytkownika, wysyłając mu e-maila z linkiem, który może kliknąć, aby się zalogować. Podczas procesu weryfikacji zweryfikowany jest też adres e-mail użytkownika.

Logowanie się przez e-maila ma wiele zalet:

  • Rejestracja i logowanie przebiegają sprawnie.
  • Mniejsze ryzyko ponownego użycia tego samego hasła w różnych aplikacjach, co może zagrażać bezpieczeństwu nawet dobrze dobranych haseł.
  • Możliwość uwierzytelnienia użytkownika, a jednocześnie potwierdzanie, że jest on prawowitym właścicielem adresu e-mail.
  • Aby się zalogować, użytkownik potrzebuje tylko dostępnego konta e-mail. Nie jest wymagane posiadanie numeru telefonu ani konta w mediach społecznościowych.
  • Użytkownik może logować się bezpiecznie bez konieczności podawania (lub zapamiętywania) hasła, co może być uciążliwe na urządzeniu mobilnym.
  • Istniejące konto użytkownika, które wcześniej logowało się przy użyciu identyfikatora e-mail (hasła lub konta sfederowanego), można przejść na wyższą wersję, aby logować się przy użyciu samego adresu e-mail. Na przykład użytkownik, który nie pamięta hasła, może się zalogować bez konieczności resetowania hasła.

Zanim zaczniesz

Skopiuj fragment kodu inicjowania z konsoli Firebase do swojego projektu w sposób opisany w artykule Dodawanie Firebase do projektu JavaScript.

Aby logować użytkowników za pomocą linku w e-mailu, musisz najpierw włączyć w projekcie Firebase metodę logowania Dostawca poczty e-mail i metodę logowania się za pomocą linku w e-mailu:

  1. W konsoli Firebase otwórz sekcję Uwierzytelnianie.
  2. Na karcie Metoda logowania włącz dostawcę E-mail/hasła. Pamiętaj, że aby korzystać z logowania za pomocą linku e-mail, musisz włączyć logowanie za pomocą adresu e-mail i hasła.
  3. W tej samej sekcji włącz metodę logowania Link w e-mailu (logowanie bez hasła).
  4. Kliknij Zapisz.

Aby zainicjować proces uwierzytelniania, pokaż użytkownikowi interfejs, który prosi o podanie adresu e-mail, a następnie wywołaj sendSignInLinkToEmail z prośbą o wysłanie przez Firebase linku uwierzytelniającego na jego adres e-mail.

  1. Utwórz obiekt ActionCodeSettings, który dostarcza Firebase z instrukcjami, jak utworzyć link do e-maila. Ustaw wartości w tych polach:

    • url: precyzyjny link do umieszczenia i wszystkie dodatkowe stany do przekazania. Domena linku należy dodać do listy autoryzowanych domen w konsoli Firebase. Aby ją znaleźć, przejdź na kartę Metoda logowania (Uwierzytelnianie -> Ustawienia).
    • android i ios: aplikacje używane po otwarciu linku logowania na urządzeniu z Androidem lub urządzeniu firmy Apple. Dowiedz się więcej o tym, jak skonfigurować Linki dynamiczne Firebase, aby otwierać linki do działań w e-mailach w aplikacjach mobilnych.
    • handleCodeInApp: ustaw wartość prawda. Operacja logowania musi być zawsze wykonywana w aplikacji, w przeciwieństwie do innych pozapasmowych działań związanych z e-mailami (resetowania hasła i potwierdzania adresu e-mail). Wynika to z faktu, że pod koniec procesu użytkownik musi być zalogowany, a jego stan uwierzytelniania musi pozostać w aplikacji.
    • dynamicLinkDomain: jeśli w projekcie zdefiniowano wiele niestandardowych domen linków dynamicznych, określ, która ma być używana, gdy link ma być otwierany przez określoną aplikację mobilną (np. example.page.link). W przeciwnym razie automatycznie zostanie wybrana pierwsza domena.

      Web Modular API

      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'
        },
        dynamicLinkDomain: 'example.page.link'
      };

      Interfejs API internetowej przestrzeni nazw

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

    Więcej informacji o ActionCodeSettings znajdziesz w sekcji Stan przekazywania w czynnościach poczty e-mail.

  2. Poproś użytkownika o podanie adresu e-mail.

  3. Wyślij link uwierzytelniania na adres e-mail użytkownika i zapisz adres e-mail użytkownika, na wypadek gdyby użytkownik logował się za pomocą adresu e-mail na tym samym urządzeniu.

    Web Modular API

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

    Interfejs API internetowej przestrzeni nazw

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

Potencjalne problemy z bezpieczeństwem

Aby zapobiec użyciu linku logowania do zalogowania się jako niezamierzony użytkownik lub na niewłaściwym urządzeniu, Uwierzytelnianie Firebase wymaga podania adresu e-mail użytkownika podczas logowania się. Aby logowanie się powiodło, ten adres e-mail musi być zgodny z adresem, na który pierwotnie przesłano link.

Możesz usprawnić ten proces w przypadku użytkowników, którzy otworzą link logowania na tym samym urządzeniu, na tym samym urządzeniu, zapisując swój adres e-mail lokalnie – na przykład przy użyciu localStorage lub plików cookie – w momencie wysyłania e-maila umożliwiającego zalogowanie się. Następnie użyj tego adresu do dokończenia procesu. Nie przekazuj adresu e-mail użytkownika w parametrach przekierowania ani nie używaj go ponownie, ponieważ może to umożliwić wstrzykiwanie sesji.

Po zakończeniu logowania wszystkie wcześniejsze niezweryfikowane mechanizmy logowania zostaną usunięte z konta użytkownika, a wszystkie istniejące sesje zostaną unieważnione. Jeśli na przykład ktoś wcześniej utworzył niezweryfikowane konto z tym samym adresem e-mail i hasłem, hasło użytkownika zostanie usunięte, aby uniemożliwić osobie podszywającej się pod inną osobę, która zgłosiła prawo własności i utworzyła niezweryfikowane konto, ponownie zalogowanie się przy użyciu niezweryfikowanego adresu e-mail i hasła.

Upewnij się też, że w środowisku produkcyjnym używasz adresu URL HTTPS, aby zapobiec potencjalnemu przechwyceniu linku przez serwery pośrednie.

Logowanie się na stronie internetowej

Format precyzyjnego linku w e-mailu jest taki sam jak format używany w przypadku pozapasmowych działań e-mail (weryfikacja adresu e-mail, resetowanie hasła i unieważnianie zmiany adresu e-mail). Uwierzytelnianie Firebase upraszcza tę weryfikację, udostępniając interfejs isSignInWithEmailLink API, który pozwala sprawdzić, czy link prowadzi do logowania za pomocą linku e-mail.

Aby dokończyć logowanie na stronie docelowej, wywołaj signInWithEmailLink, podając adres e-mail użytkownika i rzeczywisty link e-mail zawierający kod jednorazowy.

Web Modular API

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

Interfejs API internetowej przestrzeni nazw

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

Logowanie się w aplikacji mobilnej

Uwierzytelnianie Firebase używa Linków dynamicznych Firebase do wysyłania linku e-mail na urządzenie mobilne. Aby zakończyć logowanie za pomocą aplikacji mobilnej, należy skonfigurować aplikację tak, aby wykrywała przychodzący link do aplikacji, przeanalizowała precyzyjny link, a następnie logował się w taki sam sposób jak w przypadku interfejsu internetowego.

Więcej informacji o logowaniu się w aplikacji na Androida za pomocą linku e-mail znajdziesz w przewodniku po Androidzie.

Więcej informacji o tym, jak obsługiwać logowanie się za pomocą linku przez e-maila w aplikacji Apple, znajdziesz w przewodniku po platformach Apple.

Możesz też powiązać tę metodę uwierzytelniania z istniejącym użytkownikiem. Na przykład użytkownik, który wcześniej uwierzytelnił się u innego dostawcy (np. przy użyciu numeru telefonu), może dodać tę metodę logowania do swojego istniejącego konta.

Różnica będzie widoczna w drugiej połowie operacji:

Web Modular API

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

Interfejs API internetowej przestrzeni nazw

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

W ten sposób możesz też ponownie uwierzytelnić użytkownika powiązanego z linkiem e-mail przed uruchomieniem operacji poufnej.

Web Modular API

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

Interfejs API internetowej przestrzeni nazw

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

Proces ten może jednak nie zostać ukończony na innym urządzeniu, na którym pierwotny użytkownik nie był zalogowany. W takim przypadku może wyświetlić się komunikat o błędzie, który będzie wymuszał na nim otwarcie linku na tym samym urządzeniu. W linku można przekazać informacje o typie działania i identyfikatorze UID użytkownika.

Jeśli Twój projekt został utworzony 15 września 2023 r. lub później, ochrona przed wyliczeniem adresów e-mail jest domyślnie włączona. Ta funkcja zwiększa bezpieczeństwo kont użytkowników Twojego projektu, ale wyłącza metodę fetchSignInMethodsForEmail(), którą wcześniej rekomendowaliśmy w celu implementacji przepływów skoncentrowanych na identyfikatorze.

Chociaż możesz wyłączyć ochronę wyliczania adresów e-mail w projekcie, nie zalecamy tego.

Więcej informacji znajdziesz w dokumentacji dotyczącej ochrony przed wyliczeniem adresów e-mail.

Domyślny szablon e-maila dotyczącego logowania za pomocą linku

Domyślny szablon e-maila zawiera sygnaturę czasową w temacie i treści e-maila, dzięki czemu kolejne e-maile nie są zwinięte w jeden wątek, a link jest ukryty.

Ten szablon dotyczy tych języków:

Kod Język
ar arabski
zh-CN chiński (uproszczony)
zh-TW chiński (tradycyjny)
niderlandzki niderlandzki
en angielski
en-GB angielski (Wielka Brytania)
fr Francuski
de niemiecki
id Indonezyjski
jego włoski
ja japoński
ko Koreański
pl Polski
pt-BR portugalski (Brazylia)
pt-PT portugalski (Portugalia)
ru Rosyjski
es Hiszpański
ES-419 hiszpański (Ameryka Łacińska)
th tajski

Dalsze kroki

Gdy użytkownik loguje się po raz pierwszy, tworzone jest nowe konto użytkownika, które jest łączone z danymi logowania (nazwa użytkownika i hasło, numer telefonu lub informacje o dostawcy uwierzytelniania). Nowe konto jest przechowywane w ramach Twojego projektu Firebase i może być używane do identyfikowania użytkowników we wszystkich aplikacjach w Twoim projekcie niezależnie od tego, jak się on loguje.

  • Zalecanym sposobem na poznanie stanu uwierzytelniania użytkownika w aplikacjach jest ustawienie obserwatora w obiekcie Auth. Dzięki temu można uzyskać podstawowe informacje o profilu użytkownika z obiektu User. Zobacz Zarządzanie użytkownikami.

  • W regułach zabezpieczeń Bazy danych czasu rzeczywistego Firebase i Cloud Storage możesz pobrać ze zmiennej auth unikalny identyfikator użytkownika zalogowanego użytkownika i użyć go do kontrolowania, do jakich danych użytkownik ma dostęp.

Możesz zezwolić użytkownikom na logowanie się w aplikacji przy użyciu różnych dostawców uwierzytelniania, łącząc dane logowania dostawcy uwierzytelniania z istniejącym kontem użytkownika.

Aby wylogować użytkownika, wywołaj signOut:

Web Modular API

import { getAuth, signOut } from "firebase/auth";

const auth = getAuth();
signOut(auth).then(() => {
  // Sign-out successful.
}).catch((error) => {
  // An error happened.
});

Interfejs API internetowej przestrzeni nazw

firebase.auth().signOut().then(() => {
  // Sign-out successful.
}).catch((error) => {
  // An error happened.
});