احراز هویت چند عاملی را به برنامه iOS خود اضافه کنید

اگر به Firebase Authentication with Identity Platform ارتقا داده‌اید، می‌توانید احراز هویت چند مرحله‌ای از طریق پیامک را به برنامه iOS خود اضافه کنید.

احراز هویت چند عاملی امنیت برنامه شما را افزایش می‌دهد. در حالی که مهاجمان اغلب رمزهای عبور و حساب‌های کاربری شبکه‌های اجتماعی را به خطر می‌اندازند، رهگیری یک پیام متنی دشوارتر است.

قبل از اینکه شروع کنی

  1. حداقل یک ارائه‌دهنده که از احراز هویت چند عاملی پشتیبانی می‌کند را فعال کنید. همه ارائه‌دهندگان از MFA پشتیبانی می‌کنند، به جز احراز هویت از طریق تلفن، احراز هویت ناشناس و مرکز بازی اپل.

  2. مطمئن شوید که برنامه شما ایمیل‌های کاربر را تأیید می‌کند. احراز هویت چندعاملی (MFA) نیاز به تأیید ایمیل دارد. این امر مانع از آن می‌شود که افراد مخرب با ایمیلی که متعلق به آنها نیست، در یک سرویس ثبت‌نام کنند و سپس با اضافه کردن یک عامل دوم، مالک واقعی را مسدود کنند.

فعال کردن احراز هویت چند عاملی

  1. صفحه Authentication > Sign-in method را در کنسول Firebase باز کنید.

  2. در بخش پیشرفته ، تأیید هویت چند عاملی پیامکی را فعال کنید.

    همچنین باید شماره تلفن‌هایی را که قرار است برنامه خود را با آنها آزمایش کنید، وارد کنید. اگرچه اختیاری است، اما ثبت شماره تلفن‌های آزمایشی اکیداً توصیه می‌شود تا از ایجاد مشکل در طول توسعه جلوگیری شود.

  3. اگر هنوز دامنه برنامه خود را مجاز نکرده‌اید، آن را به لیست مجاز در صفحه Authentication > Settings کنسول Firebase اضافه کنید.

تأیید برنامه شما

Firebase باید تأیید کند که درخواست‌های پیامکی از برنامه شما می‌آیند. می‌توانید این کار را از دو طریق انجام دهید:

  • اعلان‌های بی‌صدای APNها : وقتی برای اولین بار وارد سیستم می‌شوید، Firebase می‌تواند یک اعلان بی‌صدا به دستگاه کاربر ارسال کند. در صورتی که برنامه اعلان را دریافت کند، احراز هویت می‌تواند ادامه یابد. توجه داشته باشید که از iOS 8.0 به بعد، نیازی نیست از کاربر بخواهید که برای استفاده از این روش، به اعلان‌های بی‌صدا اجازه دهد.

  • تأیید reCAPTCHA : اگر نمی‌توانید اعلان بی‌صدا ارسال کنید (برای مثال، به این دلیل که کاربر به‌روزرسانی پس‌زمینه را غیرفعال کرده است، یا در حال آزمایش برنامه خود در شبیه‌ساز iOS هستید)، می‌توانید از reCAPTCHA استفاده کنید. در بسیاری از موارد، reCAPTCHA بدون هیچ تعاملی با کاربر، به طور خودکار حل می‌شود.

استفاده از اعلان‌های بی‌صدا

برای فعال کردن اعلان‌های APN برای استفاده با Firebase :

  1. در Xcode، اعلان‌های فوری (push notifications) را برای پروژه خود فعال کنید .

  2. کلید احراز هویت APN خود را با استفاده از کنسول Firebase آپلود کنید (تغییرات شما به طور خودکار به Google Cloud Firebase منتقل می‌شوند). اگر از قبل کلید احراز هویت APN خود را ندارید، برای یادگیری نحوه‌ی دریافت آن به بخش پیکربندی APNها با FCM مراجعه کنید.

    1. کنسول فایربیس را باز کنید.

    2. به تنظیمات پروژه بروید.

    3. برگه پیام‌رسانی ابری را انتخاب کنید.

    4. در بخش پیکربندی برنامه iOS ، در زیر کلید احراز هویت APN ، روی «بارگذاری» کلیک کنید تا کلید احراز هویت توسعه یا کلید احراز هویت تولید یا هر دو را بارگذاری کنید. حداقل یکی از آنها لازم است.

    5. کلید خود را انتخاب کنید.

    6. شناسه کلید را برای کلید اضافه کنید. می‌توانید شناسه کلید را در قسمت گواهینامه‌ها، شناسه‌ها و پروفایل‌ها در مرکز اعضای توسعه‌دهنده اپل پیدا کنید.

    7. روی آپلود کلیک کنید.

اگر از قبل گواهی APN دارید، می‌توانید به جای آن گواهی را آپلود کنید.

استفاده از تأیید reCAPTCHA

برای فعال کردن SDK کلاینت برای استفاده از reCAPTCHA:

  1. پیکربندی پروژه خود را در Xcode باز کنید.

  2. روی نام پروژه در نمای درختی سمت چپ دوبار کلیک کنید.

  3. برنامه خود را از بخش Targets انتخاب کنید.

  4. برگه اطلاعات را انتخاب کنید.

  5. بخش انواع URL را گسترش دهید.

  6. روی دکمه + کلیک کنید.

  7. شناسه کلاینت معکوس شده خود را در فیلد طرح‌های URL وارد کنید. می‌توانید این مقدار را در فایل پیکربندی GoogleService-Info.plist با نام REVERSED_CLIENT_ID پیدا کنید.

پس از اتمام، پیکربندی شما باید مشابه تصویر زیر باشد:

طرح‌های سفارشی

به صورت اختیاری، می‌توانید نحوه نمایش SFSafariViewController یا UIWebView توسط برنامه خود را هنگام نمایش reCAPTCHA سفارشی کنید. برای انجام این کار، یک کلاس سفارشی ایجاد کنید که با پروتکل FIRAuthUIDelegate مطابقت داشته باشد و آن را به verifyPhoneNumber:UIDelegate:completion: ارسال کنید.

انتخاب الگوی ثبت نام

شما می‌توانید انتخاب کنید که آیا برنامه شما به احراز هویت چند عاملی نیاز دارد یا خیر، و چگونه و چه زمانی کاربران خود را ثبت نام کنید. برخی از الگوهای رایج عبارتند از:

  • فاکتور دوم کاربر را به عنوان بخشی از ثبت نام ثبت کنید. اگر برنامه شما نیاز به احراز هویت چند عاملی برای همه کاربران دارد، از این روش استفاده کنید. توجه داشته باشید که یک حساب کاربری برای ثبت فاکتور دوم باید دارای یک آدرس ایمیل تأیید شده باشد، بنابراین روند ثبت نام شما باید این مورد را در نظر بگیرد.

  • یک گزینه قابل رد کردن برای ثبت فاکتور دوم در طول ثبت نام ارائه دهید. برنامه‌هایی که می‌خواهند احراز هویت چند عاملی را تشویق کنند، اما الزامی به آن نداشته باشند، ممکن است این رویکرد را ترجیح دهند.

  • امکان اضافه کردن عامل دوم از صفحه مدیریت حساب یا پروفایل کاربر، به جای صفحه ثبت نام، را فراهم کنید. این کار باعث می‌شود که در طول فرآیند ثبت نام، اصطکاک به حداقل برسد، در حالی که همچنان احراز هویت چند عاملی برای کاربران حساس به امنیت در دسترس است.

  • وقتی کاربر می‌خواهد به ویژگی‌هایی با الزامات امنیتی بالاتر دسترسی پیدا کند، به تدریج یک عامل دوم اضافه کنید.

ثبت عامل دوم

برای ثبت یک عامل ثانویه جدید برای یک کاربر:

  1. کاربر را دوباره احراز هویت کنید.

  2. از کاربر بخواهید شماره تلفن خود را وارد کند.

  3. یک جلسه چند عاملی برای کاربر دریافت کنید:

    سویفت

    authResult.user.multiFactor.getSessionWithCompletion() { (session, error) in
      // ...
    }
    

    هدف-سی

    [authResult.user.multiFactor
      getSessionWithCompletion:^(FIRMultiFactorSession * _Nullable session,
                                NSError * _Nullable error) {
        // ...
    }];
    
  4. یک پیام تأیید به شماره تلفن کاربر ارسال کنید. مطمئن شوید که شماره تلفن با علامت + در ابتدای آن قالب‌بندی شده باشد و هیچ علامت نگارشی یا فاصله دیگری وجود نداشته باشد (برای مثال: +15105551234 ).

    سویفت

    // Send SMS verification code.
    PhoneAuthProvider.provider().verifyPhoneNumber(
      phoneNumber,
      uiDelegate: nil,
      multiFactorSession: session) { (verificationId, error) in
        // verificationId will be needed for enrollment completion.
    }
    

    هدف-سی

    // Send SMS verification code.
    [FIRPhoneAuthProvider.provider verifyPhoneNumber:phoneNumber
                                          UIDelegate:nil
                                  multiFactorSession:session
                                          completion:^(NSString * _Nullable verificationID,
                                                        NSError * _Nullable error) {
        // verificationId will be needed for enrollment completion.
    }];
    

    اگرچه الزامی نیست، اما بهتر است از قبل به کاربران اطلاع دهید که پیامک دریافت خواهند کرد و نرخ‌های استاندارد اعمال می‌شود.

    متد verifyPhoneNumber() فرآیند تأیید برنامه را در پس‌زمینه با استفاده از اعلان مخفی آغاز می‌کند. اگر اعلان مخفی در دسترس نباشد، به جای آن یک چالش reCAPTCHA صادر می‌شود.

  5. پس از ارسال کد پیامکی، از کاربر بخواهید کد را تأیید کند. سپس، از پاسخ آنها برای ساخت یک PhoneAuthCredential استفاده کنید:

    سویفت

    // Ask user for the verification code. Then:
    let credential = PhoneAuthProvider.provider().credential(
      withVerificationID: verificationId,
      verificationCode: verificationCode)
    

    هدف-سی

    // Ask user for the SMS verification code. Then:
    FIRPhoneAuthCredential *credential = [FIRPhoneAuthProvider.provider
                                           credentialWithVerificationID:verificationID
                                           verificationCode:kPhoneSecondFactorVerificationCode];
    
  6. مقداردهی اولیه یک شیء assertion:

    سویفت

    let assertion = PhoneMultiFactorGenerator.assertion(with: credential)
    

    هدف-سی

    FIRMultiFactorAssertion *assertion = [FIRPhoneMultiFactorGenerator assertionWithCredential:credential];
    
  7. ثبت نام را تکمیل کنید. به صورت اختیاری، می‌توانید یک نام نمایشی برای عامل دوم تعیین کنید. این برای کاربرانی که چندین عامل دوم دارند مفید است، زیرا شماره تلفن در طول فرآیند احراز هویت پنهان می‌شود (برای مثال، +1******1234).

    سویفت

    // Complete enrollment. This will update the underlying tokens
    // and trigger ID token change listener.
    user.multiFactor.enroll(with: assertion, displayName: displayName) { (error) in
      // ...
    }
    

    هدف-سی

    // Complete enrollment. This will update the underlying tokens
    // and trigger ID token change listener.
    [authResult.user.multiFactor enrollWithAssertion:assertion
                                         displayName:nil
                                          completion:^(NSError * _Nullable error) {
        // ...
    }];
    

کد زیر مثال کاملی از ثبت یک عامل دوم را نشان می‌دهد:

سویفت

let user = Auth.auth().currentUser
user?.multiFactor.getSessionWithCompletion({ (session, error) in
  // Send SMS verification code.
  PhoneAuthProvider.provider().verifyPhoneNumber(
    phoneNumber,
    uiDelegate: nil,
    multiFactorSession: session
  ) { (verificationId, error) in
    // verificationId will be needed for enrollment completion.
    // Ask user for the verification code.
    let credential = PhoneAuthProvider.provider().credential(
      withVerificationID: verificationId!,
      verificationCode: phoneSecondFactorVerificationCode)
    let assertion = PhoneMultiFactorGenerator.assertion(with: credential)
    // Complete enrollment. This will update the underlying tokens
    // and trigger ID token change listener.
    user?.multiFactor.enroll(with: assertion, displayName: displayName) { (error) in
      // ...
    }
  }
})

هدف-سی

FIRUser *user = FIRAuth.auth.currentUser;
[user.multiFactor getSessionWithCompletion:^(FIRMultiFactorSession * _Nullable session,
                                              NSError * _Nullable error) {
    // Send SMS verification code.
    [FIRPhoneAuthProvider.provider
      verifyPhoneNumber:phoneNumber
      UIDelegate:nil
      multiFactorSession:session
      completion:^(NSString * _Nullable verificationID, NSError * _Nullable error) {
        // verificationId will be needed for enrollment completion.

        // Ask user for the verification code.
        // ...

        // Then:
        FIRPhoneAuthCredential *credential =
            [FIRPhoneAuthProvider.provider credentialWithVerificationID:verificationID
                                                        verificationCode:kPhoneSecondFactorVerificationCode];
        FIRMultiFactorAssertion *assertion =
            [FIRPhoneMultiFactorGenerator assertionWithCredential:credential];

        // Complete enrollment. This will update the underlying tokens
        // and trigger ID token change listener.
        [user.multiFactor enrollWithAssertion:assertion
                                  displayName:displayName
                                    completion:^(NSError * _Nullable error) {
            // ...
        }];
    }];
}];

تبریک! شما با موفقیت یک عامل احراز هویت دوم برای یک کاربر ثبت کردید.

ورود کاربران با استفاده از فاکتور دوم

برای ورود کاربر با تأیید دو مرحله‌ای پیامکی:

  1. کاربر را با اولین فاکتور خود وارد سیستم کنید، سپس خطایی را دریافت کنید که نشان می‌دهد احراز هویت چند عاملی مورد نیاز است. این خطا شامل یک حل‌کننده، نکاتی در مورد فاکتورهای دوم ثبت‌شده و یک جلسه اساسی است که تأیید می‌کند کاربر با اولین فاکتور با موفقیت احراز هویت شده است.

    برای مثال، اگر اولین فاکتور کاربر ایمیل و رمز عبور باشد:

    سویفت

    Auth.auth().signIn(
      withEmail: email,
      password: password
    ) { (result, error) in
      let authError = error as NSError
      if authError?.code == AuthErrorCode.secondFactorRequired.rawValue {
        // The user is a multi-factor user. Second factor challenge is required.
        let resolver =
          authError!.userInfo[AuthErrorUserInfoMultiFactorResolverKey] as! MultiFactorResolver
        // ...
      } else {
        // Handle other errors such as wrong password.
      }
    }
    

    هدف-سی

    [FIRAuth.auth signInWithEmail:email
                         password:password
                       completion:^(FIRAuthDataResult * _Nullable authResult,
                                    NSError * _Nullable error) {
        if (error == nil || error.code != FIRAuthErrorCodeSecondFactorRequired) {
            // User is not enrolled with a second factor and is successfully signed in.
            // ...
        } else {
            // The user is a multi-factor user. Second factor challenge is required.
        }
    }];
    

    اگر اولین فاکتور کاربر یک ارائه‌دهنده‌ی فدرال مانند OAuth باشد، پس از فراخوانی getCredentialWith() خطا را دریافت کنید.

  2. اگر کاربر چندین عامل ثانویه ثبت کرده است، از او بپرسید که کدام یک را استفاده کند. می‌توانید شماره تلفن پنهان‌شده را با resolver.hints[selectedIndex].phoneNumber و نام نمایشی را با resolver.hints[selectedIndex].displayName دریافت کنید.

    سویفت

    // Ask user which second factor to use. Then:
    if resolver.hints[selectedIndex].factorID == PhoneMultiFactorID {
      // User selected a phone second factor.
      // ...
    } else if resolver.hints[selectedIndex].factorID == TotpMultiFactorID {
      // User selected a TOTP second factor.
      // ...
    } else {
      // Unsupported second factor.
    }
    

    هدف-سی

    FIRMultiFactorResolver *resolver =
        (FIRMultiFactorResolver *) error.userInfo[FIRAuthErrorUserInfoMultiFactorResolverKey];
    
    // Ask user which second factor to use. Then:
    FIRPhoneMultiFactorInfo *hint = (FIRPhoneMultiFactorInfo *) resolver.hints[selectedIndex];
    if (hint.factorID == FIRPhoneMultiFactorID) {
      // User selected a phone second factor.
      // ...
    } else if (hint.factorID == FIRTOTPMultiFactorID) {
      // User selected a TOTP second factor.
      // ...
    } else {
      // Unsupported second factor.
    }
    
  3. ارسال پیام تأیید به تلفن کاربر:

    سویفت

    // Send SMS verification code.
    let hint = resolver.hints[selectedIndex] as! PhoneMultiFactorInfo
    PhoneAuthProvider.provider().verifyPhoneNumber(
      with: hint,
      uiDelegate: nil,
      multiFactorSession: resolver.session
    ) { (verificationId, error) in
      // verificationId will be needed for sign-in completion.
    }
    

    هدف-سی

    // Send SMS verification code
    [FIRPhoneAuthProvider.provider
      verifyPhoneNumberWithMultiFactorInfo:hint
      UIDelegate:nil
      multiFactorSession:resolver.session
      completion:^(NSString * _Nullable verificationID, NSError * _Nullable error) {
        if (error != nil) {
            // Failed to verify phone number.
        }
    }];
    
  4. پس از ارسال کد پیامکی، از کاربر بخواهید کد را تأیید کند و از آن برای ساخت PhoneAuthCredential استفاده کنید:

    سویفت

    // Ask user for the verification code. Then:
    let credential = PhoneAuthProvider.provider().credential(
      withVerificationID: verificationId!,
      verificationCode: verificationCodeFromUser)
    

    هدف-سی

    // Ask user for the SMS verification code. Then:
    FIRPhoneAuthCredential *credential =
        [FIRPhoneAuthProvider.provider
          credentialWithVerificationID:verificationID
                      verificationCode:verificationCodeFromUser];
    
  5. یک شیء assertion را با اعتبارنامه مقداردهی اولیه کنید:

    سویفت

    let assertion = PhoneMultiFactorGenerator.assertion(with: credential)
    

    هدف-سی

    FIRMultiFactorAssertion *assertion =
        [FIRPhoneMultiFactorGenerator assertionWithCredential:credential];
    
  6. مشکل ورود به سیستم را حل کنید. سپس می‌توانید به نتیجه اصلی ورود به سیستم دسترسی پیدا کنید که شامل داده‌های استاندارد مختص ارائه‌دهنده خدمات و اطلاعات احراز هویت است:

    سویفت

    // Complete sign-in. This will also trigger the Auth state listeners.
    resolver.resolveSignIn(with: assertion) { (authResult, error) in
      // authResult 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,
      // authResult.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.
    }
    

    هدف-سی

    // Complete sign-in.
    [resolver resolveSignInWithAssertion:assertion
                              completion:^(FIRAuthDataResult * _Nullable authResult,
                                            NSError * _Nullable error) {
        if (error != nil) {
            // User successfully signed in with the second factor phone number.
        }
    }];
    

کد زیر یک مثال کامل از ورود به سیستم چند عاملی کاربر را نشان می‌دهد:

سویفت

Auth.auth().signIn(
  withEmail: email,
  password: password
) { (result, error) in
  let authError = error as NSError?
  if authError?.code == AuthErrorCode.secondFactorRequired.rawValue {
    let resolver =
      authError!.userInfo[AuthErrorUserInfoMultiFactorResolverKey] as! MultiFactorResolver

    // Ask user which second factor to use.
    // ...

    // Then:
    let hint = resolver.hints[selectedIndex] as! PhoneMultiFactorInfo

    // Send SMS verification code
    PhoneAuthProvider.provider().verifyPhoneNumber(
      with: hint,
      uiDelegate: nil,
      multiFactorSession: resolver.session
    ) { (verificationId, error) in
      if error != nil {
        // Failed to verify phone number.
      }
      // Ask user for the SMS verification code.
      // ...

      // Then:
      let credential = PhoneAuthProvider.provider().credential(
        withVerificationID: verificationId!,
        verificationCode: verificationCodeFromUser)
      let assertion = PhoneMultiFactorGenerator.assertion(with: credential)

      // Complete sign-in.
      resolver.resolveSignIn(with: assertion) { (authResult, error) in
        if error != nil {
          // User successfully signed in with the second factor phone number.
        }
      }
    }
  }
}

هدف-سی

[FIRAuth.auth signInWithEmail:email
                     password:password
                   completion:^(FIRAuthDataResult * _Nullable authResult,
                               NSError * _Nullable error) {
    if (error == nil || error.code != FIRAuthErrorCodeSecondFactorRequired) {
        // User is not enrolled with a second factor and is successfully signed in.
        // ...
    } else {
        FIRMultiFactorResolver *resolver =
            (FIRMultiFactorResolver *) error.userInfo[FIRAuthErrorUserInfoMultiFactorResolverKey];

        // Ask user which second factor to use.
        // ...

        // Then:
        FIRPhoneMultiFactorInfo *hint = (FIRPhoneMultiFactorInfo *) resolver.hints[selectedIndex];

        // Send SMS verification code
        [FIRPhoneAuthProvider.provider
          verifyPhoneNumberWithMultiFactorInfo:hint
                                    UIDelegate:nil
                            multiFactorSession:resolver.session
                                    completion:^(NSString * _Nullable verificationID,
                                                NSError * _Nullable error) {
            if (error != nil) {
                // Failed to verify phone number.
            }

            // Ask user for the SMS verification code.
            // ...

            // Then:
            FIRPhoneAuthCredential *credential =
                [FIRPhoneAuthProvider.provider
                  credentialWithVerificationID:verificationID
                              verificationCode:kPhoneSecondFactorVerificationCode];
            FIRMultiFactorAssertion *assertion =
                [FIRPhoneMultiFactorGenerator assertionWithCredential:credential];

            // Complete sign-in.
            [resolver resolveSignInWithAssertion:assertion
                                      completion:^(FIRAuthDataResult * _Nullable authResult,
                                                    NSError * _Nullable error) {
                if (error != nil) {
                    // User successfully signed in with the second factor phone number.
                }
            }];
        }];
    }
}];

تبریک! شما با موفقیت با استفاده از احراز هویت چند عاملی وارد سیستم شدید.

قدم بعدی چیست؟