Uwierzytelnianie w Firebase za pomocą numeru telefonu przy użyciu JavaScriptu

Możesz używać uwierzytelniania Firebase do logowania użytkownika, wysyłając SMS-a na jego telefon. Użytkownik loguje się za pomocą jednorazowego kodu zawartego w wiadomości SMS.

Najprostszym sposobem dodania do aplikacji funkcji logowania przy użyciu numeru telefonu jest użycie w aplikacji FirebaseUI, która zawiera widżet logowania, który implementuje procesy logowania za pomocą numeru telefonu, a także logowania opartego na haśle i sfederowanego logowania. W tym dokumencie opisujemy, jak za pomocą pakietu SDK Firebase wdrożyć proces logowania się numerem telefonu.

Zanim zaczniesz

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

Potencjalne problemy z bezpieczeństwem

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

Jeśli w swojej aplikacji korzystasz z logowania się na podstawie numeru telefonu, zaoferuj je wraz z bezpieczniejszymi metodami logowania i poinformuj użytkowników o problemach związanych z bezpieczeństwem logowania się przy użyciu numeru telefonu.

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

Aby logować użytkowników SMS-em, musisz najpierw włączyć w projekcie Firebase metodę logowania z numerem telefonu:

  1. W konsoli Firebase otwórz sekcję Uwierzytelnianie.
  2. Na stronie Metoda logowania włącz metodę logowania Numer telefonu.
  3. Jeśli w sekcji Domeny przekierowania OAuth nie ma domeny, w której będzie hostowana Twoja aplikacja, dodaj swoją domenę na tej samej stronie.

Limit próśb Firebase o zalogowanie się za pomocą numeru telefonu jest tak wysoki, że nie będzie to miało wpływu na większość aplikacji. Jeśli jednak musisz zalogować bardzo dużą liczbę użytkowników z wykorzystaniem uwierzytelniania przez telefon, konieczne może być przejście na wyższy abonament. Zobacz stronę z cenami.

Konfigurowanie weryfikatora reCAPTCHA

Zanim będzie można logować użytkowników za pomocą ich numerów telefonów, musisz skonfigurować w Firebase weryfikator reCAPTCHA. Firebase używa reCAPTCHA w celu zapobiegania nadużyciom, np. do sprawdzania, czy żądanie weryfikacji numeru telefonu pochodzi z jednej z dozwolonych domen aplikacji.

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

Obiekt RecaptchaVerifier obsługuje niewidoczne reCAPTCHA, które często weryfikuje użytkownika bez konieczności wykonywania żadnych działań, a także widżet reCAPTCHA, który zawsze wymaga interakcji użytkownika do pomyślnego ukończenia procesu.

Bazową wyrenderowaną wersję reCAPTCHA można zlokalizować zgodnie z preferencjami użytkownika, aktualizując kod języka w instancji Auth przed wyrenderowaniem reCAPTCHA. Wspomniana lokalizacja będzie mieć zastosowanie również do SMS-a zawierającego kod weryfikacyjny wysłanej do użytkownika.

Web Modular API

import { getAuth } from "firebase/auth";

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

Interfejs API internetowej przestrzeni nazw

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

Użyj niewidocznego reCAPTCHA

Aby użyć niewidocznego reCAPTCHA, utwórz obiekt RecaptchaVerifier z parametrem size ustawionym na invisible i określaj identyfikator przycisku, który przesyła formularz logowania. Przykład:

Web Modular API

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

Interfejs API internetowej przestrzeni nazw

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

Używanie widżetu reCAPTCHA

Aby użyć widocznego widżetu reCAPTCHA, utwórz na stronie element, który będzie zawierać widżet, a potem utwórz obiekt RecaptchaVerifier, podając przy tym identyfikator kontenera. Na przykład:

Web Modular API

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

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

Interfejs API internetowej przestrzeni nazw

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 zadanie reCAPTCHA lub reCAPTCHA wygaśnie, zanim użytkownik prześle formularz:

Web Modular API

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

Interfejs API internetowej przestrzeni nazw

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, wywołaj render:

Web Modular API

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

Interfejs API internetowej przestrzeni nazw

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

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

Web Modular API

const recaptchaResponse = grecaptcha.getResponse(recaptchaWidgetId);

Interfejs API internetowej przestrzeni nazw

const recaptchaResponse = grecaptcha.getResponse(recaptchaWidgetId);

Wysyłanie kodu weryfikacyjnego na telefon użytkownika

Aby zainicjować logowanie z użyciem numeru telefonu, pokaż interfejs z prośbą o podanie numeru telefonu, a następnie zadzwoń pod numer signInWithPhoneNumber, aby poprosić Firebase o wysłanie SMS-a z kodem uwierzytelniającym na telefon użytkownika:

  1. Uzyskaj numer telefonu użytkownika.

    Wymagania prawne są różne, ale zgodnie ze sprawdzoną metodą oraz ustaleniem oczekiwań użytkowników należy poinformować ich, że jeśli logują się przez telefon, mogą otrzymać SMS-a w celu weryfikacji. Obowiązują opłaty standardowe.

  2. Zadzwoń pod numer signInWithPhoneNumber, przekazując na niego numer telefonu użytkownika oraz utworzony wcześniej RecaptchaVerifier.

    Web Modular API

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

    Interfejs API internetowej przestrzeni nazw

    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ć jeszcze raz:
    grecaptcha.reset(window.recaptchaWidgetId);
    
    // Or, if you haven't stored the widget ID:
    window.recaptchaVerifier.render().then(function(widgetId) {
      grecaptcha.reset(widgetId);
    });
    

Metoda signInWithPhoneNumber wysyła użytkownikowi test reCAPTCHA, a jeśli go zaliczy, uwierzytelnianie Firebase wysyła na jego telefon SMS-a z kodem weryfikacyjnym.

Logowanie użytkownika za pomocą kodu weryfikacyjnego

Po nawiązaniu połączenia z numerem signInWithPhoneNumber poproś użytkownika o wpisanie kodu weryfikacyjnego otrzymanego SMS-em. Następnie zaloguj użytkownika, przekazując kod do metody confirm obiektu ConfirmationResult, który został przekazany do modułu obsługi realizacji zamówienia signInWithPhoneNumber (czyli do jego bloku then). Przykład:

Web Modular API

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

Interfejs API internetowej przestrzeni nazw

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 się powiedzie, użytkownik zostanie zalogowany.

Pobieranie pośredniego obiektu AuthCredential

Jeśli musisz pobrać obiekt AuthCredential dla konta użytkownika, przekaż kod weryfikacyjny z wyniku potwierdzenia i kod weryfikacyjny do aplikacji 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

W konsoli Firebase możesz skonfigurować fikcyjne numery telefonów na potrzeby programowania. Testowanie fikcyjnych numerów telefonu daje następujące korzyści:

  • Przetestuj uwierzytelnianie za pomocą numeru telefonu bez przekraczania limitu wykorzystania.
  • Przetestuj uwierzytelnianie numeru telefonu bez wysyłania faktycznego SMS-a.
  • Przeprowadzaj kolejne testy z tym samym numerem telefonu bez ograniczania limitu. Pozwala to zminimalizować ryzyko odrzucenia podczas procesu sprawdzania w sklepie z aplikacjami, jeśli weryfikator użyje do testów tego samego numeru telefonu.
  • Możesz łatwo przeprowadzać testy w środowiskach programistycznych bez żadnych dodatkowych czynności, takich jak możliwość tworzenia aplikacji w symulatorze iOS lub w emulatorze Androida bez Usług Google Play.
  • Pisz testy integracji bez blokowania przez testy zabezpieczeń, które zwykle stosują się do prawdziwych numerów telefonów w środowisku produkcyjnym.

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

  1. Upewnij się, że używane numery telefonów są fałszywe i nie istnieją. Uwierzytelnianie Firebase nie umożliwia ustawiania istniejących numerów telefonów używanych przez prawdziwych użytkowników jako numerów testowych. Jedną z opcji jest użycie 555 numerów z prefiksem w amerykańskich testowych numerach telefonów, na przykład: +1 650-555-3434
  2. Numery telefonów muszą być poprawnie sformatowane pod kątem długości i innych ograniczeń. Nadal przechodzą one taką samą weryfikację jak numer telefonu rzeczywistego użytkownika.
  3. Możesz dodać maksymalnie 10 numerów telefonów na potrzeby programowania.
  4. Używaj testowych numerów telefonów lub kodów, które trudno odgadnąć, i często je zmieniaj.

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

  1. W konsoli Firebase otwórz sekcję Uwierzytelnianie.
  2. Na karcie Metoda logowania włącz dostawcę telefonu, jeśli nie jest jeszcze włączony.
  3. Otwórz menu nawigacyjne Numery telefonów do testowania.
  4. Podaj numer telefonu, który chcesz przetestować, np. +1 650-555-3434.
  5. Podaj 6-cyfrowy kod weryfikacyjny tego numeru, np. 654321.
  6. Dodaj numer. W razie potrzeby możesz usunąć numer telefonu i jego kod. Aby to zrobić, najedź kursorem na odpowiedni wiersz i kliknij ikonę kosza.

Testy ręczne

Możesz od razu zacząć używać fikcyjnego numeru telefonu we wniosku. Dzięki temu możesz przeprowadzać testy ręczne na etapach programowania, nie powodując problemów z limitami ani ich ograniczania. Możesz też przeprowadzać testy bezpośrednio za pomocą symulatora iOS lub emulatora Androida bez zainstalowanych Usług Google Play.

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

Gdy się zalogujesz, zostanie utworzony użytkownik Firebase z tym numerem telefonu. Działa on tak samo i ma takie same właściwości jak prawdziwy użytkownik numeru telefonu. W ten sam sposób może również korzystać z Bazy danych czasu rzeczywistego/Cloud Firestore oraz innych usług. Token tożsamości wygenerowany podczas tego procesu ma taki sam podpis jak prawdziwy użytkownik numeru telefonu.

Możesz też ustawić rolę testową dla tych użytkowników za pomocą roszczeń niestandardowych, aby odróżnić ich jako fałszywych użytkowników, jeśli chcesz jeszcze bardziej ograniczyć dostęp do nich.

Testowanie integracji

Oprócz testowania ręcznego Uwierzytelnianie Firebase udostępnia interfejsy API, które ułatwiają pisanie testów integracji na potrzeby testowania uwierzytelniania telefonicznego. Te interfejsy API wyłączają weryfikację aplikacji przez wyłączenie wymogu reCAPTCHA w internecie oraz cichych powiadomień push na urządzeniach z iOS. Dzięki temu możliwe jest testowanie automatyzacji w tych procesach i łatwiejsze ich wdrożenie. Rozwiązanie pozwala też testować procesy błyskawicznej weryfikacji na Androidzie.

W przypadku witryny ustaw appVerificationDisabledForTesting na true przed wyrenderowaniem obiektu firebase.auth.RecaptchaVerifier. Spowoduje to automatyczne zamknięcie reCAPTCHA, umożliwiając przekazanie numeru telefonu bez wpisywania go ręcznie. Pamiętaj, że pomimo wyłączenia reCAPTCHA przy użyciu niefikcyjnego numeru telefonu i tak nie uda się dokończyć logowania. Za pomocą tego interfejsu 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 pozorowane weryfikację aplikacji reCAPTCHA zachowują się inaczej, gdy weryfikacja aplikacji jest wyłączona:

  • Widoczna reCAPTCHA: gdy widoczna reCAPTCHA jest renderowana przez appVerifier.render(), automatycznie wyłącza się po ułamku sekundy. Jest to równoważne z kliknięciem przez użytkownika reCAPTCHA zaraz po wyrenderowaniu. Odpowiedź reCAPTCHA wygaśnie po pewnym czasie, a następnie zostanie automatycznie rozwiązany ponownie.
  • Niewidoczna reCAPTCHA: niewidoczna reCAPTCHA nie jest rozpoznawana automatycznie podczas renderowania, ale robi to w wywołaniu appVerifier.verify() lub gdy zakotwiczony przycisk reCAPTCHA zostanie kliknięty po ułamku sekundy opóźnienia. Podobnie odpowiedź wygaśnie po pewnym czasie i zostanie automatycznie rozwiązana dopiero po wywołaniu appVerifier.verify() lub po ponownym kliknięciu przycisku zakotwiczenia przycisku reCAPTCHA.

Po zakończeniu testu reCAPTCHA w sposób zgodny z oczekiwaniami uruchamiana jest odpowiednia funkcja wywołania zwrotnego z fałszywą odpowiedzią. Jeśli określisz także wywołanie zwrotne o dacie wygaśnięcia, zostanie ono aktywowane po wygaśnięciu.

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