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

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

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

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

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

  2. مطمئن شوید که برنامه شما ایمیل های کاربر را تأیید می کند. وزارت امور خارجه به تأیید ایمیل نیاز دارد. این امر مانع از ثبت نام عوامل مخرب در سرویسی با ایمیلی می شود که متعلق به آنها نیست و سپس با افزودن عامل دوم، مالک واقعی را قفل می کند.

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

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

  2. در بخش Advanced ، SMS Multi-factor Authentication را فعال کنید.

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

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

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

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

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

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

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

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

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

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

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

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

    3. برگه Cloud Messaging را انتخاب کنید.

    4. در بخش APNs Authentication key ، در بخش پیکربندی برنامه iOS ، روی آپلود کلیک کنید.

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

    هدف-C

    [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.
    }
    

    هدف-C

    // 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)
    

    هدف-C

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

    سریع

    let assertion = PhoneMultiFactorGenerator.assertion(with: credential)
    

    هدف-C

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

    سریع

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

    هدف-C

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

هدف-C

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

    هدف-C

    [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.
    }
    

    هدف-C

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

    هدف-C

    // 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)
    

    هدف-C

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

    سریع

    let assertion = PhoneMultiFactorGenerator.assertion(with: credential)
    

    هدف-C

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

    هدف-C

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

هدف-C

[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.
                }
            }];
        }];
    }
}];

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

بعدش چی