اگر به Firebase Authentication with Identity Platform ارتقا دادهاید، میتوانید اصالتسنجی چندعاملی پیامکی به برنامه وب خود اضافه کنید.
اصالتسنجی چندعاملی امنیت برنامه شما را افزایش میدهد. درحالیکه مهاجمان اغلب گذرواژهها و حسابهای اجتماعی را بهخطر میاندازند، رهگیری پیامک دشوارتر است.
قبل از شروع
حداقل یک ارائهدهنده را که از اصالتسنجی چندعاملی پشتیبانی میکند فعال کنید. همه ارائهدهندگان از «احراز هویت چندعاملی» پشتیبانی میکنند، بهجز احراز هویت تلفنی، احراز هویت ناشناس، و Apple Game Center.
مناطقی را که قصد دارید از اصالتسنجی پیامکی استفاده کنید فعال کنید. Authentication از خطمشی منطقه پیامک کاملاً مسدودکننده استفاده میکند که به ایجاد پروژههایتان در وضعیت امنتر بهطور پیشفرض کمک میکند.
مطمئن شوید که برنامه شما ایمیلهای کاربر را درستیسنجی میکند. «احراز هویت چندعاملی» به درستیسنجی ایمیل نیاز دارد. این کار مانع میشود عاملان بدخواه با ایمیلی که متعلق به آنها نیست در سرویسی ثبتنام کنند و سپس با افزودن عامل دوم، مالک واقعی را از دسترسی به حسابش محروم کنند.
استفاده از چند مستأجری
اگر درحال فعال کردن اصالتسنجی چندعاملی برای استفاده در محیط چند مستأجره هستید، مطمئن شوید مراحل زیر را (علاوهبر بقیه دستورالعملهای این سند) تکمیل کنید:
در کنسول Google Cloud، مستأجری را که میخواهید با آن کار کنید انتخاب کنید.
در کدتان، فیلد
tenantIdرا در نمونهAuthروی شناسه مستأجرتان تنظیم کنید. برای مثال:Web
import { getAuth } from "firebase/auth"; const auth = getAuth(app); auth.tenantId = "myTenantId1";Web
firebase.auth().tenantId = 'myTenantId1';
فعال کردن اصالتسنجی چندعاملی
در کنسول Firebase، به امنیت > اصالتسنجی بروید.
در زبانه روش ورود به سیستم، در بخش پیشرفته، اصالتسنجی چندعاملی پیامکی را فعال کنید.
همچنین باید شماره تلفنهایی را که با آنها برنامهتان را آزمایش خواهید کرد وارد کنید. اگرچه ثبت شماره تلفنهای آزمایشی اختیاری است، اما بهشدت توصیه میشود که برای اجتناب از محدود شدن درطول توسعه، این کار را انجام دهید.
اگر قبلاً این کار را نکردهاید، دامنه برنامهتان را مجاز کنید:
در کنسول Firebase، به امنیت > اصالتسنجی > زبانه تنظیمات بروید.
در بخش دامنههای مجاز، روی افزودن دامنه کلیک کنید و دامنه خود را اضافه کنید.
انتخاب الگوی ثبت
میتوانید انتخاب کنید که آیا برنامه شما به اصالتسنجی چندعاملی نیاز دارد یا نه، و چگونه و چه زمانی کاربران خود را ثبت کنید. برخیاز الگوهای رایج عبارتاند از:
عامل دوم کاربر را بهعنوان بخشی از ثبتنام ثبت کنید. اگر برنامه شما برای همه کاربران به اصالتسنجی چندعاملی نیاز دارد، از این روش استفاده کنید.
گزینهای قابلرد کردن برای ثبت عامل دوم درطول ثبتنام ارائه دهید. برنامههایی که میخواهند اصالتسنجی چندعاملی را تشویق کنند، اما آن را الزامی نکنند، ممکن است این رویکرد را ترجیح دهند.
امکان افزودن عامل دوم از صفحه مدیریت حساب یا نمایه کاربر، بهجای صفحه ثبتنام، را فراهم کنید. این کار اصطکاک درطول فرایند ثبتنام را به حداقل میرساند و درعینحال، اصالتسنجی چندعاملی را برای کاربران حساس به امنیت دردسترس قرار میدهد.
وقتی کاربر بخواهد به ویژگیهایی با الزامات امنیتی بیشتر دسترسی پیدا کند، بهتدریج افزودن عامل دوم را الزامی کنید.
راهاندازی درستیسنج reCAPTCHA
قبلاز اینکه بتوانید کدهای پیامکی ارسال کنید، باید درستیسنج reCAPTCHA را پیکربندی کنید. Authentication از reCAPTCHA برای جلوگیری از سوءاستفاده استفاده میکند و مطمئن میشود که درخواستهای درستیسنجی شماره تلفن از یکی از دامنههای مجاز برنامهتان ارسال میشود.
لازم نیست کارخواه reCAPTCHA را بهصورت دستی راهاندازی کنید؛
شیء RecaptchaVerifier در کیت توسعه نرمافزار کارخواه بهطور خودکار هرگونه کلید و رمز کارخواه لازم را ایجاد و مقداردهی اولیه میکند.
استفاده از reCAPTCHA نامرئی
شیء RecaptchaVerifier از
reCAPTCHA نامرئی پشتیبانی میکند،
که اغلب میتواند کاربر را بدون نیاز به هیچ تعاملی درستیسنجی کند. برای استفاده از
reCAPTCHA نامرئی، RecaptchaVerifier را با پارامتر size تنظیمشده
روی invisible ایجاد کنید و شناسه عنصر رابط کاربری را که ثبتنام چندعاملی را شروع میکند
مشخص کنید:
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();
}
});
استفاده از ابزارک reCAPTCHA
برای استفاده از ابزارک نمایان reCAPTCHA، عنصر HTML را برای نگهداری ابزارک ایجاد کنید، سپس شیء RecaptchaVerifier را با شناسه ظرف UI ایجاد کنید. همچنین میتوانید بهصورت اختیاری بازخوانهایی تنظیم کنید که وقتی
reCAPTCHA حل میشود یا منقضی میشود فراخوانی میشوند:
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.
// ...
}
});
پیشرندر کردن reCAPTCHA
درصورت تمایل، میتوانید reCAPTCHA را قبلاز شروع ثبتنام تأیید دومرحلهای پیشپرداز کنید:
Web
recaptchaVerifier.render()
.then(function (widgetId) {
window.recaptchaWidgetId = widgetId;
});
Web
recaptchaVerifier.render()
.then(function(widgetId) {
window.recaptchaWidgetId = widgetId;
});
پساز اینکه render() حل شد، شناسه ابزارک reCAPTCHA را دریافت میکنید که میتوانید از آن برای
تماس با
میانای برنامهسازی کاربردی reCAPTCHA استفاده کنید:
var recaptchaResponse = grecaptcha.getResponse(window.recaptchaWidgetId);
RecaptchaVerifier این منطق را با روش verify انتزاع میکند، بنابراین نیازی نیست متغیر grecaptcha را مستقیماً مدیریت کنید.
درحال ثبت عامل دوم
برای ثبت عامل ثانویه جدید برای کاربر:
کاربر را مجدداً اصالتسنجی کنید.
از کاربر بخواهید شماره تلفنش را وارد کند.
مطمئن شوید رضایت مناسب را از آنها دریافت کردهاید.درستیسنج reCAPTCHA را همانطور که در بخش قبلی نشان داده شده است مقداردهی اولیه کنید. اگر نمونه RecaptchaVerifier قبلاً پیکربندی شده است، از این مرحله رد شوید:
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');دریافت جلسه چندعاملی برای کاربر:
Web
import { multiFactor } from "firebase/auth"; multiFactor(user).getSession().then(function (multiFactorSession) { // ... });Web
user.multiFactor.getSession().then(function(multiFactorSession) { // ... })شیء
PhoneInfoOptionsرا با شماره تلفن کاربر و جلسه چندعاملی مقداردهی اولیه کنید: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 };پیام درستیسنجی به تلفن کاربر ارسال کنید:
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. })اگرچه الزامی نیست، اما بهتر است ازقبل به کاربران اطلاع دهید که پیامک دریافت خواهند کرد و نرخهای استاندارد اعمال میشود.
اگر درخواست ناموفق بود، reCAPTCHA را بازنشانی کنید، سپس مرحله قبلی را تکرار کنید تا کاربر بتواند دوباره امتحان کند. توجه داشته باشید که
verifyPhoneNumber()وقتی خطایی ایجاد میکند، بهطور خودکار reCAPTCHA را بازنشانی میکند، زیرا کدهای reCAPTCHA فقط یکبار قابل استفاده هستند.Web
recaptchaVerifier.clear();Web
recaptchaVerifier.clear();پساز ارسال کد پیامکی، از کاربر بخواهید کد را درستیسنجی کند:
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);شیء
MultiFactorAssertionرا باPhoneAuthCredentialمقداردهی اولیه کنید:Web
import { PhoneMultiFactorGenerator } from "firebase/auth"; const multiFactorAssertion = PhoneMultiFactorGenerator.assertion(cred);Web
var multiFactorAssertion = firebase.auth.PhoneMultiFactorGenerator.assertion(cred);ثبتنام را تکمیل کنید. درصورت تمایل، میتوانید نام نمایشی برای عامل دوم مشخص کنید. این ویژگی برای کاربرانی که عوامل دوم متعددی دارند مفید است، زیرا شماره تلفن درطول جریان اصالتسنجی پوشانده میشود (برای مثال، +۱******۱۲۳۴).
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');
کد زیر نمونه کاملی از ثبت عامل دوم را نشان میدهد:
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);
});
تبریک! عامل اصالتسنجی دوم را باموفقیت برای کاربری ثبت کردید.
ورود کاربران به سیستم با عامل دوم
برای وارد کردن کاربر به سیستم با درستیسنجی پیامکی دوعاملی:
کاربر را با عامل اولش به سیستم وارد کنید، سپس خطای
auth/multi-factor-auth-requiredرا دریافت کنید. این خطا حاوی حلکننده، نکتههایی درباره عاملهای دوم ثبتشده، و جلسه زیربنایی است که ثابت میکند کاربر با عامل اول بهدرستی اصالتسنجی شده است.برای مثال، اگر عامل اول کاربر ایمیل و گذرواژه بود:
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. } ... });اگر عامل اول کاربر ارائهدهنده فدرال باشد، مثل OAuth، SAML، یا OIDC، خطا را پساز فراخوانی
signInWithPopup()یاsignInWithRedirect()دریافت کنید.اگر کاربر چندین عامل ثانویه ثبتشده دارد، از او بپرسید از کدام عامل میخواهد استفاده کند:
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. }درستیسنج reCAPTCHA را همانطور که در بخش قبلی نشان داده شده است مقداردهی اولیه کنید. اگر نمونه RecaptchaVerifier قبلاً پیکربندی شده است، از این مرحله رد شوید:
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');شیء
PhoneInfoOptionsرا با شماره تلفن کاربر و جلسه چندعاملی مقداردهی اولیه کنید. این مقادیر درresolverشیء ارسالشده به خطایauth/multi-factor-auth-requiredقرار دارند:Web
const phoneInfoOptions = { multiFactorHint: resolver.hints[selectedIndex], session: resolver.session };Web
var phoneInfoOptions = { multiFactorHint: resolver.hints[selectedIndex], session: resolver.session };پیام درستیسنجی به تلفن کاربر ارسال کنید:
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. })اگر درخواست ناموفق بود، reCAPTCHA را بازنشانی کنید، سپس مرحله قبلی را تکرار کنید تا کاربر بتواند دوباره امتحان کند:
Web
recaptchaVerifier.clear();Web
recaptchaVerifier.clear();پساز ارسال کد پیامکی، از کاربر بخواهید کد را درستیسنجی کند:
Web
const cred = PhoneAuthProvider.credential(verificationId, verificationCode);Web
// Ask user for the verification code. Then: var cred = firebase.auth.PhoneAuthProvider.credential(verificationId, verificationCode);شیء
MultiFactorAssertionرا باPhoneAuthCredentialمقداردهی اولیه کنید:Web
const multiFactorAssertion = PhoneMultiFactorGenerator.assertion(cred);Web
var multiFactorAssertion = firebase.auth.PhoneMultiFactorGenerator.assertion(cred);برای تکمیل اصالتسنجی ثانویه، با
resolver.resolveSignIn()تماس بگیرید. سپس میتوانید به نتیجه ورود به سیستم اصلی که شامل دادههای خاص ارائهدهنده استاندارد و اطلاعات اعتباری اصالتسنجی است دسترسی پیدا کنید: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. });
کد زیر نمونه کاملی از ورود به سیستم کاربر چندعاملی را نشان میدهد:
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.
} ...
});
تبریک! کاربری را باموفقیت بااستفاده از اصالتسنجی چندعاملی به سیستم وارد کردید.
مرحله بعدی چیست
- مدیریت کاربران دارای چندعامل بهصورت برنامهریزیشده با Admin SDK.