افزودن اصالت‌سنجی چندعاملی به برنامه iOS

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

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

قبل از شروع

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

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

فعال کردن اصالت‌سنجی چندعاملی

  1. در کنسول Firebase، به امنیت > اصالت‌سنجی بروید.

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

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

  3. اگر قبلاً این کار را نکرده‌اید، دامنه برنامه‌تان را مجاز کنید:

    1. در کنسول Firebase، به امنیت > اصالت‌سنجی > زبانه تنظیمات بروید.

    2. در بخش دامنه‌های مجاز، روی افزودن دامنه کلیک کنید و دامنه خود را اضافه کنید.

درحال درستی‌سنجی برنامه شما

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

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

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

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

برای فعال کردن اعلان‌های APNs برای استفاده با Authentication:

  1. در Xcode، اعلان‌های لحظه‌ای را فعال کنید برای پروژه‌تان.

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

    1. در کنسول Firebase، به تنظیمات > کلی بروید. سپس، روی زبانه پیام‌رسانی ابری کلیک کنید.

    2. در بخش کلید اصالت‌سنجی APNs، در بخش پیکربندی برنامه iOS، روی بارگذاری کلیک کنید تا کلید اصالت‌سنجی توسعه، یا کلید اصالت‌سنجی تولید، یا هر دو را بارگذاری کنید. حداقل یکی لازم است.

    3. کلیدتان را انتخاب کنید.

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

    5. روی بارگذاری کلیک کنید.

اگر ازقبل گواهینامه APNs دارید، می‌توانید گواهینامه را بارگذاری کنید.

استفاده از درستی‌سنجی reCAPTCHA

برای فعال کردن کیت توسعه نرم‌افزار کارخواه برای استفاده از reCAPTCHA:

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

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

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

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

  5. بخش انواع نشانی وب را ازهم باز کنید.

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

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

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

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

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

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

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

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

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

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

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

درحال ثبت عامل دوم

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

  1. کاربر را مجدداً اصالت‌سنجی کنید.

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

    مطمئن شوید رضایت مناسب را از آن‌ها دریافت کرده‌اید.
  3. دریافت جلسه چندعاملی برای کاربر:

    Swift

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

    Objective-C

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

    Swift

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

    Objective-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 استفاده کنید:

    Swift

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

    Objective-C

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

    Swift

    let assertion = PhoneMultiFactorGenerator.assertion(with: credential)
    

    Objective-C

    FIRMultiFactorAssertion *assertion = [FIRPhoneMultiFactorGenerator assertionWithCredential:credential];
    
  7. ثبت‌نام را تکمیل کنید. درصورت تمایل، می‌توانید نام نمایشی برای عامل دوم مشخص کنید. این ویژگی برای کاربرانی که عوامل دوم متعددی دارند مفید است، زیرا شماره تلفن درطول جریان اصالت‌سنجی پوشانده می‌شود (برای مثال، ‎+۱******۱۲۳۴).

    Swift

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

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

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

Swift

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

Objective-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. کاربر را با عامل اولش به سیستم وارد کنید، سپس خطایی را که نشان می‌دهد اصالت‌سنجی چندعاملی لازم است دریافت کنید. این خطا شامل یک حل‌کننده، نکته‌هایی درباره عامل‌های دوم ثبت‌شده، و یک جلسه زیربنایی است که ثابت می‌کند کاربر با عامل اول با موفقیت اصالت‌سنجی کرده است.

    برای مثال، اگر عامل اول کاربر ایمیل و گذرواژه بود:

    Swift

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

    Objective-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 دریافت کنید.

    Swift

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

    Objective-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. پیام درستی‌سنجی به تلفن کاربر ارسال کنید:

    Swift

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

    Objective-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 استفاده کند:

    Swift

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

    Objective-C

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

    Swift

    let assertion = PhoneMultiFactorGenerator.assertion(with: credential)
    

    Objective-C

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

    Swift

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

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

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

Swift

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

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

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

مرحله بعدی چیست