Uwierzytelniaj w Firebase za pomocą numeru telefonu z użyciem JavaScriptu

Możesz użyć Firebase Authentication, aby zalogować użytkownika, wysyłając SMS-a na jego telefon. Użytkownik loguje się za pomocą jednorazowego kodu zawartego w SMS-ie.

Najprostszym sposobem dodania do aplikacji logowania za pomocą numeru telefonu jest użycie FirebaseUI, które zawiera gotowy widżet logowania implementujący przepływy logowania za pomocą numeru telefonu, a także logowania opartego na haśle i logowania sfederowanego. W tym dokumencie opisujemy, jak wdrożyć proces logowania za pomocą numeru telefonu przy użyciu pakietu SDK Firebase.

Zanim zaczniesz

Jeśli jeszcze tego nie zrobisz, skopiuj fragment kodu inicjującego z Firebasekonsoli do projektu zgodnie z instrukcjami w artykule Dodawanie Firebase do projektu JavaScript.

Potencjalne problemy z bezpieczeństwem

Uwierzytelnianie za pomocą samego numeru telefonu, choć wygodne, jest mniej bezpieczne niż inne dostępne metody, ponieważ własność numeru telefonu można łatwo przenieść między użytkownikami. Na urządzeniach z wieloma profilami użytkowników każdy użytkownik, który może odbierać SMS-y, może zalogować się na konto za pomocą numeru telefonu urządzenia.

Jeśli w aplikacji używasz logowania za pomocą numeru telefonu, powinieneś/powinnaś oferować je wraz z bezpieczniejszymi metodami logowania i informować użytkowników o kompromisach w zakresie bezpieczeństwa związanych z logowaniem za pomocą numeru telefonu.

Włączanie logowania za pomocą numeru telefonu w projekcie w Firebase

Aby logować użytkowników za pomocą SMS-ów, musisz najpierw włączyć w projekcie w Firebase metodę logowania za pomocą numeru telefonu:

  1. W konsoli Firebase otwórz Bezpieczeństwo > Uwierzytelnianie.
  2. Na karcie Metoda logowania włącz dostawcę logowania Telefon.
  3. Ustaw zasady dotyczące regionów, do których chcesz zezwolić na wysyłanie SMS-ów lub im tego zabronić. Ustawienie zasad dotyczących regionu SMS-ów może pomóc chronić aplikacje przed nadużyciami związanymi z SMS-ami. W przypadku nowych projektów domyślne zasady nie zezwalają na żadne regiony.
    1. W konsoli Firebase otwórz Zabezpieczenia > Uwierzytelnianie > karta Ustawienia.
    2. W sekcji Zasady dotyczące regionów SMS skonfiguruj zasady dotyczące regionów SMS.
  4. Jeśli nie masz jeszcze autoryzowanej domeny aplikacji:
    1. W konsoli Firebase otwórz Zabezpieczenia > Uwierzytelnianie > karta Ustawienia.
    2. W sekcji Autoryzowane domeny kliknij Dodaj domenę i dodaj swoją domenę.

    Pamiętaj, że w przypadku uwierzytelniania za pomocą telefonu localhost nie jest dozwolony jako hostowana domena.

Konfigurowanie weryfikatora reCAPTCHA

Zanim zaczniesz logować użytkowników za pomocą ich numerów telefonów, musisz skonfigurować weryfikator reCAPTCHA Firebase. Firebase używa reCAPTCHA, aby zapobiegać nadużyciom, np. poprzez upewnianie się, że prośba o weryfikację numeru telefonu pochodzi z jednej z dozwolonych domen aplikacji.

Nie musisz ręcznie konfigurować klienta reCAPTCHA. Gdy używasz obiektu RecaptchaVerifier pakietu SDK Firebase, Firebase automatycznie tworzy i obsługuje wszystkie niezbędne klucze i klucze tajne klienta.

Obiekt RecaptchaVerifier obsługuje niewidoczną reCAPTCHA, która często może zweryfikować użytkownika bez konieczności podejmowania przez niego żadnych działań, a także widżet reCAPTCHA, który zawsze wymaga interakcji użytkownika, aby można było go pomyślnie ukończyć.

Renderowaną reCAPTCHA można dostosować do preferencji użytkownika, aktualizując kod języka w instancji Auth przed renderowaniem reCAPTCHA. Wspomniana lokalizacja będzie też dotyczyć SMS-a wysyłanego do użytkownika, który zawiera kod weryfikacyjny.

Web

import { getAuth } from "firebase/auth";

const auth = getAuth();
auth.languageCode = 'it';
// To apply the default browser preference instead of explicitly setting it.
// auth.useDeviceLanguage();

Web

firebase.auth().languageCode = 'it';
// To apply the default browser preference instead of explicitly setting it.
// firebase.auth().useDeviceLanguage();

Korzystanie z niewidocznej reCAPTCHA

Aby użyć niewidocznej reCAPTCHA, utwórz obiekt RecaptchaVerifier z parametrem size ustawionym na invisible, podając identyfikator przycisku, który przesyła formularz logowania. Przykład:

Web

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

const auth = getAuth();
window.recaptchaVerifier = new RecaptchaVerifier(auth, 'sign-in-button', {
  'size': 'invisible',
  'callback': (response) => {
    // reCAPTCHA solved, allow signInWithPhoneNumber.
    onSignInSubmit();
  }
});

Web

window.recaptchaVerifier = new firebase.auth.RecaptchaVerifier('sign-in-button', {
  'size': 'invisible',
  'callback': (response) => {
    // reCAPTCHA solved, allow signInWithPhoneNumber.
    onSignInSubmit();
  }
});

Korzystanie z widżetu reCAPTCHA

Aby użyć widocznego widżetu reCAPTCHA, utwórz w witrynie element, który będzie go zawierać, a następnie utwórz obiekt RecaptchaVerifier, podając przy tym identyfikator kontenera. Przykład:

Web

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

const auth = getAuth();
window.recaptchaVerifier = new RecaptchaVerifier(auth, 'recaptcha-container', {});

Web

window.recaptchaVerifier = new firebase.auth.RecaptchaVerifier('recaptcha-container');

Opcjonalnie: określ parametry reCAPTCHA

Opcjonalnie możesz ustawić funkcje wywołania zwrotnego w obiekcie RecaptchaVerifier, które są wywoływane, gdy użytkownik rozwiąże reCAPTCHA lub gdy reCAPTCHA wygaśnie, zanim użytkownik prześle formularz:

Web

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

const auth = getAuth();
window.recaptchaVerifier = new RecaptchaVerifier(auth, 'recaptcha-container', {
  'size': 'normal',
  'callback': (response) => {
    // reCAPTCHA solved, allow signInWithPhoneNumber.
    // ...
  },
  'expired-callback': () => {
    // Response expired. Ask user to solve reCAPTCHA again.
    // ...
  }
});

Web

window.recaptchaVerifier = new firebase.auth.RecaptchaVerifier('recaptcha-container', {
  'size': 'normal',
  'callback': (response) => {
    // reCAPTCHA solved, allow signInWithPhoneNumber.
    // ...
  },
  'expired-callback': () => {
    // Response expired. Ask user to solve reCAPTCHA again.
    // ...
  }
});

Opcjonalnie: wstępne renderowanie reCAPTCHA

Jeśli chcesz wstępnie wyrenderować reCAPTCHA przed przesłaniem prośby o zalogowanie się, wywołaj funkcję render:

Web

recaptchaVerifier.render().then((widgetId) => {
  window.recaptchaWidgetId = widgetId;
});

Web

recaptchaVerifier.render().then((widgetId) => {
  window.recaptchaWidgetId = widgetId;
});

Po rozwiązaniu obietnicy render otrzymasz identyfikator widżetu reCAPTCHA, którego możesz użyć do wywoływania interfejsu API reCAPTCHA:

Web

const recaptchaResponse = grecaptcha.getResponse(recaptchaWidgetId);

Web

const recaptchaResponse = grecaptcha.getResponse(recaptchaWidgetId);

Wysyłanie kodu weryfikacyjnego na telefon użytkownika

Aby rozpocząć logowanie przy użyciu numeru telefonu, wyświetl użytkownikowi interfejs z prośbą o podanie numeru telefonu, a następnie wywołaj funkcję signInWithPhoneNumber, aby poprosić Firebase o wysłanie kodu uwierzytelniającego na telefon użytkownika w SMS-ie:

  1. Uzyskaj numer telefonu użytkownika.

    Wymagania prawne są różne, ale zgodnie ze sprawdzonymi metodami i aby spełnić oczekiwania użytkowników, należy poinformować ich, że jeśli używają logowania za pomocą telefonu, mogą otrzymać SMS-a z prośbą o weryfikację, a w takim przypadku obowiązują standardowe stawki.

  2. Wywołaj funkcję signInWithPhoneNumber, przekazując do niej numer telefonu użytkownika i utworzony wcześniej RecaptchaVerifier.

    Web

    import { getAuth, signInWithPhoneNumber } from "firebase/auth";
    
    const phoneNumber = getPhoneNumberFromUserInput();
    const appVerifier = window.recaptchaVerifier;
    
    const auth = getAuth();
    signInWithPhoneNumber(auth, phoneNumber, appVerifier)
        .then((confirmationResult) => {
          // SMS sent. Prompt user to type the code from the message, then sign the
          // user in with confirmationResult.confirm(code).
          window.confirmationResult = confirmationResult;
          // ...
        }).catch((error) => {
          // Error; SMS not sent
          // ...
        });

    Web

    const phoneNumber = getPhoneNumberFromUserInput();
    const appVerifier = window.recaptchaVerifier;
    firebase.auth().signInWithPhoneNumber(phoneNumber, appVerifier)
        .then((confirmationResult) => {
          // SMS sent. Prompt user to type the code from the message, then sign the
          // user in with confirmationResult.confirm(code).
          window.confirmationResult = confirmationResult;
          // ...
        }).catch((error) => {
          // Error; SMS not sent
          // ...
        });
    Jeśli signInWithPhoneNumber spowoduje błąd, zresetuj reCAPTCHA, aby użytkownik mógł spróbować ponownie:
    grecaptcha.reset(window.recaptchaWidgetId);
    
    // Or, if you haven't stored the widget ID:
    window.recaptchaVerifier.render().then(function(widgetId) {
      grecaptcha.reset(widgetId);
    });

Metoda signInWithPhoneNumber wyświetla użytkownikowi zadanie reCAPTCHA, a jeśli użytkownik je rozwiąże, wysyła żądanie do Firebase Authentication, aby wysłać SMS-a z kodem weryfikacyjnym na telefon użytkownika.

Logowanie użytkownika za pomocą kodu weryfikacyjnego

Po udanej próbie wywołania funkcji signInWithPhoneNumber poproś użytkownika o wpisanie kodu weryfikacyjnego otrzymanego w SMS-ie. Następnie zaloguj użytkownika, przekazując kod do metody confirm obiektu ConfirmationResult, który został przekazany do modułu obsługi realizacji signInWithPhoneNumber (czyli bloku then). Przykład:

Web

const code = getCodeFromUserInput();
confirmationResult.confirm(code).then((result) => {
  // User signed in successfully.
  const user = result.user;
  // ...
}).catch((error) => {
  // User couldn't sign in (bad verification code?)
  // ...
});

Web

const code = getCodeFromUserInput();
confirmationResult.confirm(code).then((result) => {
  // User signed in successfully.
  const user = result.user;
  // ...
}).catch((error) => {
  // User couldn't sign in (bad verification code?)
  // ...
});

Jeśli wywołanie confirm zakończy się powodzeniem, użytkownik zostanie zalogowany.

Pobieranie pośredniego obiektu AuthCredential

Jeśli musisz uzyskać obiekt AuthCredential dla konta użytkownika, przekaż kod weryfikacyjny z wyniku potwierdzenia i kod weryfikacyjny do PhoneAuthProvider.credential zamiast wywoływać confirm:

var credential = firebase.auth.PhoneAuthProvider.credential(confirmationResult.verificationId, code);

Następnie możesz zalogować użytkownika za pomocą danych logowania:

firebase.auth().signInWithCredential(credential);

Testowanie za pomocą fikcyjnych numerów telefonów

Możesz skonfigurować fikcyjne numery telefonów na potrzeby programowania za pomocą konsoli Firebase. Testowanie z użyciem fikcyjnych numerów telefonów zapewnia te korzyści:

  • Testuj uwierzytelnianie numeru telefonu bez wykorzystywania limitu użycia.
  • Testowanie uwierzytelniania numeru telefonu bez wysyłania SMS-a.
  • Przeprowadzaj kolejne testy z użyciem tego samego numeru telefonu bez ograniczeń. Zmniejsza to ryzyko odrzucenia aplikacji podczas procesu sprawdzania w sklepie z aplikacjami, jeśli osoba sprawdzająca użyje tego samego numeru telefonu do testowania.
  • Łatwe testowanie w środowiskach programistycznych bez dodatkowego wysiłku, np. możliwość tworzenia aplikacji w symulatorze iOS lub emulatorze Androida bez Usług Google Play.
  • Pisz testy integracyjne bez blokowania przez kontrole bezpieczeństwa, które są zwykle stosowane w przypadku prawdziwych numerów telefonów w środowisku produkcyjnym.

Fikcyjne numery telefonów muszą spełniać te wymagania:

  1. Używaj numerów telefonów, które są fikcyjne i nie istnieją.Firebase Authentication nie zezwala na ustawianie jako numerów testowych istniejących numerów telefonów używanych przez prawdziwych użytkowników. Jedną z opcji jest używanie numerów z prefiksem 555 jako amerykańskich testowych numerów telefonów, np.:+1 650-555-3434
  2. Numery telefonów muszą być prawidłowo sformatowane pod względem długości i innych ograniczeń. Będą one podlegać tej samej weryfikacji co numery telefonów prawdziwych użytkowników.
  3. Możesz dodać maksymalnie 10 numerów telefonów na potrzeby programowania.
  4. Używaj testowych numerów telefonów i kodów, które są trudne do odgadnięcia i często je zmieniaj.

Tworzenie fikcyjnych numerów telefonów i kodów weryfikacyjnych

  1. W konsoli Firebase otwórz Bezpieczeństwo > Uwierzytelnianie.
  2. Na karcie Metoda logowania włącz dostawcę logowania Telefon, jeśli jeszcze tego nie zrobiono.
  3. Rozwiń sekcję Numery telefonu do testowania.
  4. Podaj numer telefonu, który chcesz przetestować, np. +1 650-555-3434.
  5. Podaj 6-cyfrowy kod weryfikacyjny dla tego numeru, np. 654321.
  6. Kliknij Dodaj przy każdym numerze. W razie potrzeby możesz usunąć numer telefonu i kod, najeżdżając kursorem na odpowiedni wiersz i klikając ikonę kosza.

Testy ręczne

Możesz od razu zacząć używać w aplikacji fikcyjnego numeru telefonu. Umożliwia to przeprowadzanie testów ręcznych na etapach programowania bez problemów z limitami lub ograniczaniem przepustowości. Możesz też testować bezpośrednio w symulatorze iOS lub emulatorze Androida bez zainstalowanych Usług Google Play.

Gdy podasz fikcyjny numer telefonu i wyślesz kod weryfikacyjny, nie zostanie wysłany żaden SMS. Zamiast tego musisz podać wcześniej skonfigurowany kod weryfikacyjny, aby dokończyć logowanie.

Po zakończeniu logowania tworzony jest użytkownik Firebase z tym numerem telefonu. Użytkownik zachowuje się i ma takie same właściwości jak użytkownik z prawdziwym numerem telefonu. Może też korzystać z Realtime Database/Cloud Firestore i innych usług w ten sam sposób. Token identyfikacyjny wygenerowany w tym procesie ma taki sam podpis jak w przypadku użytkownika z prawdziwym numerem telefonu.

Inną opcją jest ustawienie roli testowej za pomocą niestandardowych roszczeń w przypadku tych użytkowników, aby odróżnić ich od prawdziwych użytkowników, jeśli chcesz dodatkowo ograniczyć dostęp.

Testy integracji

Oprócz testów ręcznych Firebase Authentication udostępnia interfejsy API, które pomagają pisać testy integracyjne na potrzeby testowania uwierzytelniania telefonicznego. Te interfejsy API wyłączają weryfikację aplikacji, wyłączając wymaganie reCAPTCHA w przypadku powiadomień push w sieci i cichych powiadomień push na iOS. Umożliwia to testowanie automatyzacji w tych procesach i ułatwia jego wdrożenie. Umożliwiają też testowanie na Androidzie procesów natychmiastowej weryfikacji.

W przypadku stron internetowych ustaw wartość appVerificationDisabledForTesting na true przed wyrenderowaniem elementu firebase.auth.RecaptchaVerifier. Rozwiązuje to automatycznie test reCAPTCHA, dzięki czemu możesz podać numer telefonu bez ręcznego rozwiązywania testu. Uwaga: nawet jeśli reCAPTCHA jest wyłączona, użycie numeru telefonu, który nie jest fikcyjny, nadal uniemożliwi zalogowanie się. W tym interfejsie API można używać tylko fikcyjnych numerów telefonów.

// Turn off phone auth app verification.
firebase.auth().settings.appVerificationDisabledForTesting = true;

var phoneNumber = "+16505554567";
var testVerificationCode = "123456";

// This will render a fake reCAPTCHA as appVerificationDisabledForTesting is true.
// This will resolve after rendering without app verification.
var appVerifier = new firebase.auth.RecaptchaVerifier('recaptcha-container');
// signInWithPhoneNumber will call appVerifier.verify() which will resolve with a fake
// reCAPTCHA response.
firebase.auth().signInWithPhoneNumber(phoneNumber, appVerifier)
    .then(function (confirmationResult) {
      // confirmationResult can resolve with the fictional testVerificationCode above.
      return confirmationResult.confirm(testVerificationCode)
    }).catch(function (error) {
      // Error; SMS not sent
      // ...
    });

Widoczne i niewidoczne weryfikatory aplikacji reCAPTCHA działają inaczej, gdy weryfikacja aplikacji jest wyłączona:

  • Widoczna reCAPTCHA: gdy widoczna reCAPTCHA jest renderowana za pomocą appVerifier.render(), automatycznie rozwiązuje się po ułamku sekundy. Odpowiada to kliknięciu reCAPTCHA przez użytkownika natychmiast po renderowaniu. Odpowiedź reCAPTCHA wygasa po pewnym czasie, a następnie ponownie rozwiązuje się automatycznie.
  • Niewidoczna reCAPTCHA: niewidoczna reCAPTCHA nie rozwiązuje się automatycznie podczas renderowania, ale robi to podczas wywołania appVerifier.verify() lub gdy po ułamku sekundy opóźnienia kliknie się element zakotwiczenia przycisku reCAPTCHA. Podobnie odpowiedź wygaśnie po pewnym czasie i zostanie automatycznie rozwiązana dopiero po wywołaniu funkcji appVerifier.verify() lub ponownym kliknięciu elementu zakotwiczonego przycisku reCAPTCHA.

Gdy fałszywa reCAPTCHA zostanie rozwiązana, odpowiednia funkcja wywołania zwrotnego zostanie wywołana zgodnie z oczekiwaniami z fałszywą odpowiedzią. Jeśli określono też wywołanie zwrotne wygaśnięcia, zostanie ono wywołane po wygaśnięciu.

Dalsze kroki

Gdy użytkownik zaloguje się po raz pierwszy, zostanie utworzone nowe konto użytkownika i połączone z danymi logowania, czyli nazwą użytkownika i hasłem, numerem telefonu lub informacjami o dostawcy uwierzytelniania, za pomocą których użytkownik się zalogował. To nowe konto jest przechowywane w ramach projektu w Firebase i może służyć do identyfikowania użytkownika we wszystkich aplikacjach w projekcie, niezależnie od sposobu logowania.

  • Zalecanym sposobem sprawdzania stanu uwierzytelniania użytkownika w aplikacjach jest ustawienie obserwatora na obiekcie Auth. Następnie możesz pobrać podstawowe informacje o profilu użytkownika z obiektu User. Więcej informacji znajdziesz w artykule Zarządzanie użytkownikami.

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

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

Aby wylogować użytkownika, wywołaj funkcję 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.
});