Jeśli korzystasz już z Firebase Authentication with Identity Platform, możesz włączyć uwierzytelnianie wielopoziomowe z użyciem SMS-ów. do aplikacji internetowej.
Uwierzytelnianie wielopoziomowe zwiększa bezpieczeństwo aplikacji. Osoby przeprowadzające atak często wykradają hasła i konta społecznościowe, przechwytywanie SMS-a jest co jest utrudnione.
Zanim zaczniesz
Włącz co najmniej 1 dostawcę, który obsługuje uwierzytelnianie wielopoziomowe. Każdy dostawca obsługuje MFA z wyjątkiem uwierzytelniania telefonicznego, uwierzytelniania anonimowego i Apple Game Center
Włącz regiony, w których chcesz używać uwierzytelniania SMS. Firebase używa całkowicie blokujących zasad dotyczących regionów SMS-ów, które pomaga domyślnie tworzyć projekty w bezpieczniejszym stanie.
Upewnij się, że Twoja aplikacja weryfikuje adresy e-mail użytkowników. MFA wymaga weryfikacji adresu e-mail. Dzięki temu hakerzy nie będą mogli zarejestrować się w usłudze za pomocą adresu e-mail. których nie należy, a następnie zablokować rzeczywistego właściciela, dodając współczynnik konwersji.
Korzystanie ze środowiska wielu najemców
Jeśli włączysz uwierzytelnianie wielopoziomowe w aplikacji wielu najemców, upewnij się, aby wykonać poniższe czynności (oprócz pozostałych instrukcji w tym dokumencie):
W konsoli Google Cloud wybierz najemcę, z którym chcesz współpracować.
W kodzie ustaw pole
tenantIdw wystąpieniuAuthna identyfikator najemcy. Przykład:Web
import { getAuth } from "firebase/auth"; const auth = getAuth(app); auth.tenantId = "myTenantId1";Web
firebase.auth().tenantId = 'myTenantId1';
Włączanie uwierzytelniania wielopoziomowego
Otwórz sekcję Uwierzytelnianie > Metoda logowania stronie konsoli Firebase.
W sekcji Zaawansowane włącz Uwierzytelnianie wielopoziomowe przez SMS-y.
Wpisz też numery telefonów, które będą używane podczas testowania aplikacji. Chociaż jest to opcjonalne, zdecydowanie zalecamy zarejestrowanie testowych numerów telefonów, i uniknąć ograniczenia w trakcie programowania.
Jeśli domena aplikacji nie została jeszcze autoryzowana, dodaj ją do zezwolenia na liście Uwierzytelnianie > Ustawienia stronie konsoli Firebase.
Wybór wzorca rejestracji
Możesz zdecydować, czy Twoja aplikacja wymaga uwierzytelniania wielopoziomowego i w jaki sposób i kiedy zarejestrować użytkowników. Oto kilka często spotykanych wzorców:
Zarejestruj drugi składnik logowania użytkownika w ramach rejestracji. Użyj tej , jeśli Twoja aplikacja wymaga uwierzytelniania wielopoziomowego dla wszystkich użytkowników.
Zaoferować możliwą do pominięcia opcję rejestracji drugiego składnika podczas rejestracji. aplikacji; które chcą zachęcić do uwierzytelniania wielopoziomowego, ale nie wymagają tego, preferować tę metodę.
umożliwia dodanie drugiego składnika z konta lub profilu użytkownika. na stronie zarządzania, a nie na ekranie rejestracji. Pozwala to zminimalizować tarcie podczas rejestracji, a jednocześnie stosować uwierzytelnianie dwuskładnikowe. dostępna dla użytkowników, którzy zwracają uwagę na bezpieczeństwo.
Wymagaj stopniowego dodawania drugiego składnika, gdy użytkownik chce uzyskać dostęp funkcje o wyższych wymaganiach w zakresie bezpieczeństwa.
Konfigurowanie weryfikatora reCAPTCHA
Zanim będzie można wysyłać kody SMS, musisz skonfigurować weryfikatora reCAPTCHA. Firebase używa reCAPTCHA, aby zapobiegać nadużyciom, sprawdzając, czy: prośby o weryfikację numeru telefonu pochodzą z jednej z dozwolonych domen w Twojej aplikacji.
Nie musisz ręcznie konfigurować klienta reCAPTCHA. pakiet SDK klienta
Obiekt RecaptchaVerifier automatycznie tworzy i inicjuje niezbędne
Klucze i tajne klucze klienta.
Używanie niewidocznego reCAPTCHA
Obiekt RecaptchaVerifier obsługuje
niewidoczne reCAPTCHA,
które często weryfikują użytkownika bez konieczności interakcji. Aby użyć
niewidoczna reCAPTCHA, utwórz RecaptchaVerifier z zestawem parametrów size
na invisible i podaj identyfikator elementu interfejsu, który rozpoczyna uwierzytelnianie wielopoziomowe
rejestracja:
Web
import { RecaptchaVerifier, getAuth } from "firebase/auth";
const recaptchaVerifier = new RecaptchaVerifier(getAuth(), "sign-in-button", {
"size": "invisible",
"callback": function(response) {
// reCAPTCHA solved, you can proceed with
// phoneAuthProvider.verifyPhoneNumber(...).
onSolvedRecaptcha();
}
});
Web
var recaptchaVerifier = new firebase.auth.RecaptchaVerifier('sign-in-button', {
'size': 'invisible',
'callback': function(response) {
// reCAPTCHA solved, you can proceed with phoneAuthProvider.verifyPhoneNumber(...).
onSolvedRecaptcha();
}
});
Korzystanie z widżetu reCAPTCHA
Aby użyć widocznego widżetu reCAPTCHA, utwórz element HTML do umieszczenia
widżet, a potem utwórz obiekt RecaptchaVerifier z identyfikatorem tego interfejsu.
kontenera. Możesz też opcjonalnie ustawić wywołania zwrotne, które są wywoływane, gdy
reCAPTCHA jest rozwiązany lub wygasa:
Web
import { RecaptchaVerifier, getAuth } from "firebase/auth";
const recaptchaVerifier = new RecaptchaVerifier(
getAuth(),
"recaptcha-container",
// Optional reCAPTCHA parameters.
{
"size": "normal",
"callback": function(response) {
// reCAPTCHA solved, you can proceed with
// phoneAuthProvider.verifyPhoneNumber(...).
onSolvedRecaptcha();
},
"expired-callback": function() {
// Response expired. Ask user to solve reCAPTCHA again.
// ...
}
}
);
Web
var recaptchaVerifier = new firebase.auth.RecaptchaVerifier(
'recaptcha-container',
// Optional reCAPTCHA parameters.
{
'size': 'normal',
'callback': function(response) {
// reCAPTCHA solved, you can proceed with phoneAuthProvider.verifyPhoneNumber(...).
// ...
onSolvedRecaptcha();
},
'expired-callback': function() {
// Response expired. Ask user to solve reCAPTCHA again.
// ...
}
});
Wstępne renderowanie reCAPTCHA
Opcjonalnie możesz wstępnie wyrenderować reCAPTCHA przed uruchomieniem dwuskładnikowego rejestracja:
Web
recaptchaVerifier.render()
.then(function (widgetId) {
window.recaptchaWidgetId = widgetId;
});
Web
recaptchaVerifier.render()
.then(function(widgetId) {
window.recaptchaWidgetId = widgetId;
});
Po rozwiązaniu problemu render() otrzymasz identyfikator widżetu reCAPTCHA, którego możesz użyć
dzwonić pod numery
Interfejs API reCAPTCHA:
var recaptchaResponse = grecaptcha.getResponse(window.recaptchaWidgetId);
RecaptchaVerifier wyodrębnia tę logikę przy użyciu metody verify, więc nie musisz bezpośrednio obsługiwać zmiennej grecaptcha.
Rejestrowanie drugiego składnika
Aby zarejestrować nowy czynnik dodatkowy dla użytkownika:
Ponownie uwierzytelnij użytkownika.
Poproś użytkownika o podanie numeru telefonu.
Zainicjuj weryfikatora reCAPTCHA zgodnie z instrukcjami w poprzedniej sekcji. Pomiń ten krok, jeśli instancja RecaptchaVerifier jest już skonfigurowana:
Web
import { RecaptchaVerifier, getAuth } from "firebase/auth"; const recaptchaVerifier = new RecaptchaVerifier( getAuth(),'recaptcha-container-id', undefined);Web
var recaptchaVerifier = new firebase.auth.RecaptchaVerifier('recaptcha-container-id');Pobierz sesję wielopoziomową dla użytkownika:
Web
import { multiFactor } from "firebase/auth"; multiFactor(user).getSession().then(function (multiFactorSession) { // ... });Web
user.multiFactor.getSession().then(function(multiFactorSession) { // ... })Zainicjuj obiekt
PhoneInfoOptionsnumerem telefonu użytkownika sesja wielopoziomowa:Web
// Specify the phone number and pass the MFA session. const phoneInfoOptions = { phoneNumber: phoneNumber, session: multiFactorSession };Web
// Specify the phone number and pass the MFA session. var phoneInfoOptions = { phoneNumber: phoneNumber, session: multiFactorSession };Wyślij wiadomość weryfikacyjną na telefon użytkownika:
Web
import { PhoneAuthProvider } from "firebase/auth"; const phoneAuthProvider = new PhoneAuthProvider(auth); phoneAuthProvider.verifyPhoneNumber(phoneInfoOptions, recaptchaVerifier) .then(function (verificationId) { // verificationId will be needed to complete enrollment. });Web
var phoneAuthProvider = new firebase.auth.PhoneAuthProvider(); // Send SMS verification code. return phoneAuthProvider.verifyPhoneNumber(phoneInfoOptions, recaptchaVerifier) .then(function(verificationId) { // verificationId will be needed for enrollment completion. })Chociaż nie jest to wymagane, warto wcześniej poinformować użytkowników, że otrzyma SMS-a, co spowoduje naliczenie standardowej opłaty.
Jeśli żądanie się nie powiedzie, zresetuj reCAPTCHA i powtórz poprzedni krok. aby użytkownik mógł spróbować jeszcze raz. Pamiętaj, że
verifyPhoneNumber()będzie automatycznie resetuje reCAPTCHA po zgłoszeniu błędu, jak Tokeny reCAPTCHA są przeznaczone tylko do jednorazowego użytku.Web
recaptchaVerifier.clear();Web
recaptchaVerifier.clear();Gdy zostanie wysłany SMS, poproś użytkownika o jego potwierdzenie:
Web
// Ask user for the verification code. Then: const cred = PhoneAuthProvider.credential(verificationId, verificationCode);Web
// Ask user for the verification code. Then: var cred = firebase.auth.PhoneAuthProvider.credential(verificationId, verificationCode);Zainicjuj obiekt
MultiFactorAssertionza pomocą interfejsuPhoneAuthCredential:Web
import { PhoneMultiFactorGenerator } from "firebase/auth"; const multiFactorAssertion = PhoneMultiFactorGenerator.assertion(cred);Web
var multiFactorAssertion = firebase.auth.PhoneMultiFactorGenerator.assertion(cred);Dokończ rejestrację. Opcjonalnie możesz określić wyświetlaną nazwę dla atrybutu drugiego czynnika. Jest to przydatne w przypadku użytkowników z wieloma współczynnikami sekundowymi, ponieważ podczas uwierzytelniania numer telefonu jest maskowany (na np. +1******1234).
Web
// Complete enrollment. This will update the underlying tokens // and trigger ID token change listener. multiFactor(user).enroll(multiFactorAssertion, "My personal phone number");Web
// Complete enrollment. This will update the underlying tokens // and trigger ID token change listener. user.multiFactor.enroll(multiFactorAssertion, 'My personal phone number');
Poniżej znajdziesz pełny przykład rejestrowania drugiego składnika:
Web
import {
multiFactor, PhoneAuthProvider, PhoneMultiFactorGenerator,
RecaptchaVerifier, getAuth
} from "firebase/auth";
const recaptchaVerifier = new RecaptchaVerifier(getAuth(),
'recaptcha-container-id', undefined);
multiFactor(user).getSession()
.then(function (multiFactorSession) {
// Specify the phone number and pass the MFA session.
const phoneInfoOptions = {
phoneNumber: phoneNumber,
session: multiFactorSession
};
const phoneAuthProvider = new PhoneAuthProvider(auth);
// Send SMS verification code.
return phoneAuthProvider.verifyPhoneNumber(phoneInfoOptions, recaptchaVerifier);
}).then(function (verificationId) {
// Ask user for the verification code. Then:
const cred = PhoneAuthProvider.credential(verificationId, verificationCode);
const multiFactorAssertion = PhoneMultiFactorGenerator.assertion(cred);
// Complete enrollment.
return multiFactor(user).enroll(multiFactorAssertion, mfaDisplayName);
});
Web
var recaptchaVerifier = new firebase.auth.RecaptchaVerifier('recaptcha-container-id');
user.multiFactor.getSession().then(function(multiFactorSession) {
// Specify the phone number and pass the MFA session.
var phoneInfoOptions = {
phoneNumber: phoneNumber,
session: multiFactorSession
};
var phoneAuthProvider = new firebase.auth.PhoneAuthProvider();
// Send SMS verification code.
return phoneAuthProvider.verifyPhoneNumber(
phoneInfoOptions, recaptchaVerifier);
})
.then(function(verificationId) {
// Ask user for the verification code.
var cred = firebase.auth.PhoneAuthProvider.credential(verificationId, verificationCode);
var multiFactorAssertion = firebase.auth.PhoneMultiFactorGenerator.assertion(cred);
// Complete enrollment.
return user.multiFactor.enroll(multiFactorAssertion, mfaDisplayName);
});
Gratulacje! Udało Ci się zarejestrować drugi etap uwierzytelniania dla użytkownika.
Logowanie użytkowników przy użyciu drugiego składnika
Aby zalogować użytkownika za pomocą weryfikacji dwuetapowej przez SMS:
Zaloguj użytkownika na podstawie pierwszego składnika, a potem przechwyć
auth/multi-factor-auth-requiredbłąd. Ten błąd zawiera resolver, wskazówki dotyczące zarejestrowanych drugich czynników oraz bazowa sesja (udało się uwierzytelnić użytkownika za pomocą pierwszego składnika).Jeśli np. pierwszym czynnikiem były adres e-mail i hasło użytkownika:
Web
import { getAuth, signInWithEmailAndPassword, getMultiFactorResolver} from "firebase/auth"; const auth = getAuth(); signInWithEmailAndPassword(auth, email, password) .then(function (userCredential) { // User successfully signed in and is not enrolled with a second factor. }) .catch(function (error) { if (error.code == 'auth/multi-factor-auth-required') { // The user is a multi-factor user. Second factor challenge is required. resolver = getMultiFactorResolver(auth, error); // ... } else if (error.code == 'auth/wrong-password') { // Handle other errors such as wrong password. } });Web
firebase.auth().signInWithEmailAndPassword(email, password) .then(function(userCredential) { // User successfully signed in and is not enrolled with a second factor. }) .catch(function(error) { if (error.code == 'auth/multi-factor-auth-required') { // The user is a multi-factor user. Second factor challenge is required. resolver = error.resolver; // ... } else if (error.code == 'auth/wrong-password') { // Handle other errors such as wrong password. } ... });Jeśli pierwszym składnikiem użytkownika jest dostawca sfederowany, taki jak OAuth, SAML lub OIDC, wykryj błąd po wywołaniu usługi
signInWithPopup()lubsignInWithRedirect()Jeśli użytkownik ma zarejestrowanych kilka czynników dodatkowych, zapytaj go, który do użycia:
Web
// Ask user which second factor to use. // You can get the masked phone number via resolver.hints[selectedIndex].phoneNumber // You can get the display name via resolver.hints[selectedIndex].displayName if (resolver.hints[selectedIndex].factorId === PhoneMultiFactorGenerator.FACTOR_ID) { // User selected a phone second factor. // ... } else if (resolver.hints[selectedIndex].factorId === TotpMultiFactorGenerator.FACTOR_ID) { // User selected a TOTP second factor. // ... } else { // Unsupported second factor. }Web
// Ask user which second factor to use. // You can get the masked phone number via resolver.hints[selectedIndex].phoneNumber // You can get the display name via resolver.hints[selectedIndex].displayName if (resolver.hints[selectedIndex].factorId === firebase.auth.PhoneMultiFactorGenerator.FACTOR_ID) { // User selected a phone second factor. // ... } else if (resolver.hints[selectedIndex].factorId === firebase.auth.TotpMultiFactorGenerator.FACTOR_ID) { // User selected a TOTP second factor. // ... } else { // Unsupported second factor. }Zainicjuj weryfikatora reCAPTCHA zgodnie z instrukcjami w poprzedniej sekcji. Pomiń ten krok, jeśli instancja RecaptchaVerifier jest już skonfigurowana:
Web
import { RecaptchaVerifier, getAuth } from "firebase/auth"; recaptchaVerifier = new RecaptchaVerifier(getAuth(), 'recaptcha-container-id', undefined);Web
var recaptchaVerifier = new firebase.auth.RecaptchaVerifier('recaptcha-container-id');Zainicjuj obiekt
PhoneInfoOptionsnumerem telefonu użytkownika sesji wielopoziomowej. Wartości te znajdują się w sekcjiresolverobiekt przekazany do błęduauth/multi-factor-auth-required:Web
const phoneInfoOptions = { multiFactorHint: resolver.hints[selectedIndex], session: resolver.session };Web
var phoneInfoOptions = { multiFactorHint: resolver.hints[selectedIndex], session: resolver.session };Wyślij wiadomość weryfikacyjną na telefon użytkownika:
Web
// Send SMS verification code. const phoneAuthProvider = new PhoneAuthProvider(auth); phoneAuthProvider.verifyPhoneNumber(phoneInfoOptions, recaptchaVerifier) .then(function (verificationId) { // verificationId will be needed for sign-in completion. });Web
var phoneAuthProvider = new firebase.auth.PhoneAuthProvider(); // Send SMS verification code. return phoneAuthProvider.verifyPhoneNumber(phoneInfoOptions, recaptchaVerifier) .then(function(verificationId) { // verificationId will be needed for sign-in completion. })Jeśli żądanie się nie powiedzie, zresetuj reCAPTCHA i powtórz poprzedni krok. aby użytkownik mógł spróbować ponownie:
Web
recaptchaVerifier.clear();Web
recaptchaVerifier.clear();Gdy zostanie wysłany SMS, poproś użytkownika o jego potwierdzenie:
Web
const cred = PhoneAuthProvider.credential(verificationId, verificationCode);Web
// Ask user for the verification code. Then: var cred = firebase.auth.PhoneAuthProvider.credential(verificationId, verificationCode);Zainicjuj obiekt
MultiFactorAssertionza pomocą interfejsuPhoneAuthCredential:Web
const multiFactorAssertion = PhoneMultiFactorGenerator.assertion(cred);Web
var multiFactorAssertion = firebase.auth.PhoneMultiFactorGenerator.assertion(cred);Wywołaj
resolver.resolveSignIn(), aby ukończyć dodatkowe uwierzytelnianie. Następnie możesz uzyskać dostęp do pierwotnych wyników logowania, które obejmują standardowe dane uwierzytelniające i dane uwierzytelniające specyficzne dla dostawcy:Web
// Complete sign-in. This will also trigger the Auth state listeners. resolver.resolveSignIn(multiFactorAssertion) .then(function (userCredential) { // userCredential will also contain the user, additionalUserInfo, optional // credential (null for email/password) associated with the first factor sign-in. // For example, if the user signed in with Google as a first factor, // userCredential.additionalUserInfo will contain data related to Google // provider that the user signed in with. // - user.credential contains the Google OAuth credential. // - user.credential.accessToken contains the Google OAuth access token. // - user.credential.idToken contains the Google OAuth ID token. });Web
// Complete sign-in. This will also trigger the Auth state listeners. resolver.resolveSignIn(multiFactorAssertion) .then(function(userCredential) { // userCredential will also contain the user, additionalUserInfo, optional // credential (null for email/password) associated with the first factor sign-in. // For example, if the user signed in with Google as a first factor, // userCredential.additionalUserInfo will contain data related to Google provider that // the user signed in with. // user.credential contains the Google OAuth credential. // user.credential.accessToken contains the Google OAuth access token. // user.credential.idToken contains the Google OAuth ID token. });
Poniżej znajdziesz pełny przykład logowania użytkownika wielopoziomowego:
Web
import {
getAuth,
getMultiFactorResolver,
PhoneAuthProvider,
PhoneMultiFactorGenerator,
RecaptchaVerifier,
signInWithEmailAndPassword
} from "firebase/auth";
const recaptchaVerifier = new RecaptchaVerifier(getAuth(),
'recaptcha-container-id', undefined);
const auth = getAuth();
signInWithEmailAndPassword(auth, email, password)
.then(function (userCredential) {
// User is not enrolled with a second factor and is successfully
// signed in.
// ...
})
.catch(function (error) {
if (error.code == 'auth/multi-factor-auth-required') {
const resolver = getMultiFactorResolver(auth, error);
// Ask user which second factor to use.
if (resolver.hints[selectedIndex].factorId ===
PhoneMultiFactorGenerator.FACTOR_ID) {
const phoneInfoOptions = {
multiFactorHint: resolver.hints[selectedIndex],
session: resolver.session
};
const phoneAuthProvider = new PhoneAuthProvider(auth);
// Send SMS verification code
return phoneAuthProvider.verifyPhoneNumber(phoneInfoOptions, recaptchaVerifier)
.then(function (verificationId) {
// Ask user for the SMS verification code. Then:
const cred = PhoneAuthProvider.credential(
verificationId, verificationCode);
const multiFactorAssertion =
PhoneMultiFactorGenerator.assertion(cred);
// Complete sign-in.
return resolver.resolveSignIn(multiFactorAssertion)
})
.then(function (userCredential) {
// User successfully signed in with the second factor phone number.
});
} else if (resolver.hints[selectedIndex].factorId ===
TotpMultiFactorGenerator.FACTOR_ID) {
// Handle TOTP MFA.
// ...
} else {
// Unsupported second factor.
}
} else if (error.code == 'auth/wrong-password') {
// Handle other errors such as wrong password.
}
});
Web
var resolver;
firebase.auth().signInWithEmailAndPassword(email, password)
.then(function(userCredential) {
// User is not enrolled with a second factor and is successfully signed in.
// ...
})
.catch(function(error) {
if (error.code == 'auth/multi-factor-auth-required') {
resolver = error.resolver;
// Ask user which second factor to use.
if (resolver.hints[selectedIndex].factorId ===
firebase.auth.PhoneMultiFactorGenerator.FACTOR_ID) {
var phoneInfoOptions = {
multiFactorHint: resolver.hints[selectedIndex],
session: resolver.session
};
var phoneAuthProvider = new firebase.auth.PhoneAuthProvider();
// Send SMS verification code
return phoneAuthProvider.verifyPhoneNumber(phoneInfoOptions, recaptchaVerifier)
.then(function(verificationId) {
// Ask user for the SMS verification code.
var cred = firebase.auth.PhoneAuthProvider.credential(
verificationId, verificationCode);
var multiFactorAssertion =
firebase.auth.PhoneMultiFactorGenerator.assertion(cred);
// Complete sign-in.
return resolver.resolveSignIn(multiFactorAssertion)
})
.then(function(userCredential) {
// User successfully signed in with the second factor phone number.
});
} else if (resolver.hints[selectedIndex].factorId ===
firebase.auth.TotpMultiFactorGenerator.FACTOR_ID) {
// Handle TOTP MFA.
// ...
} else {
// Unsupported second factor.
}
} else if (error.code == 'auth/wrong-password') {
// Handle other errors such as wrong password.
} ...
});
Gratulacje! Udało Ci się zalogować użytkownika za pomocą uwierzytelniania wielopoziomowego uwierzytelnianie.
Co dalej?
- Zarządzanie użytkownikami uwierzytelniania wielopoziomowego automatycznie za pomocą Admin SDK.