หากคุณอัปเกรดเป็น Firebase Authentication ด้วย Identity Platform แล้ว คุณจะเพิ่มการตรวจสอบสิทธิ์แบบหลายปัจจัยทาง SMS ให้กับแอป iOS ได้
การรับรองความถูกต้องแบบหลายปัจจัยช่วยเพิ่มความปลอดภัยของแอปของคุณ แม้ว่าผู้โจมตีมักจะบุกรุกรหัสผ่านและบัญชีโซเชียล แต่การสกัดกั้นข้อความนั้นยากกว่า
ก่อนที่คุณจะเริ่ม
เปิดใช้งานผู้ให้บริการอย่างน้อยหนึ่งรายที่รองรับการรับรองความถูกต้องแบบหลายปัจจัย ผู้ให้บริการทุกรายรองรับ MFA ยกเว้น การตรวจสอบสิทธิ์ทางโทรศัพท์ การตรวจสอบแบบไม่เปิดเผยตัวตน และ Apple Game Center
ตรวจสอบให้แน่ใจว่าแอปของคุณกำลังยืนยันอีเมลของผู้ใช้ MFA กำหนดให้มีการยืนยันอีเมล วิธีนี้จะป้องกันไม่ให้ผู้ไม่ประสงค์ดีลงทะเบียนใช้บริการด้วยอีเมลที่พวกเขาไม่ได้เป็นเจ้าของ จากนั้นจึงล็อกเจ้าของที่แท้จริงออกด้วยการเพิ่มปัจจัยที่สอง
การเปิดใช้งานการรับรองความถูกต้องแบบหลายปัจจัย
เปิดหน้า การตรวจสอบสิทธิ์ > วิธีการลงชื่อเข้าใช้ ของคอนโซล Firebase
ในส่วน ขั้นสูง ให้เปิดใช้งาน SMS Multi-factor Authentication
คุณควรป้อนหมายเลขโทรศัพท์ที่จะใช้ทดสอบแอปด้วย แม้ว่าจะเป็นทางเลือก แต่ขอแนะนำอย่างยิ่งให้ลงทะเบียนหมายเลขโทรศัพท์ทดสอบเพื่อหลีกเลี่ยงการควบคุมปริมาณระหว่างการพัฒนา
หากคุณยังไม่ได้อนุญาตโดเมนของแอปของคุณ ให้เพิ่มลงในรายการอนุญาตบนหน้า การตรวจสอบสิทธิ์ > การตั้งค่า ของคอนโซล Firebase
กำลังยืนยันแอปของคุณ
Firebase จำเป็นต้องยืนยันว่าคำขอ SMS มาจากแอปของคุณ คุณสามารถทำได้สองวิธี:
การแจ้งเตือน APN แบบไม่มีเสียง : เมื่อคุณลงชื่อเข้าใช้ผู้ใช้เป็นครั้งแรก Firebase จะสามารถส่งการแจ้งเตือนแบบพุชแบบไม่มีเสียงไปยังอุปกรณ์ของผู้ใช้ได้ การตรวจสอบสิทธิ์สามารถดำเนินการต่อได้หากแอปได้รับการแจ้งเตือน โปรดทราบว่าตั้งแต่ iOS 8.0 เป็นต้นไป คุณไม่จำเป็นต้องขอให้ผู้ใช้อนุญาตการแจ้งเตือนแบบพุชเพื่อใช้วิธีนี้
การยืนยัน reCAPTCHA : หากคุณไม่สามารถส่งการแจ้งเตือนแบบเงียบได้ (เช่น เนื่องจากผู้ใช้ปิดใช้งานการรีเฟรชพื้นหลัง หรือคุณกำลังทดสอบแอปของคุณในเครื่องจำลอง iOS) คุณสามารถใช้ reCAPTCHA ได้ ในหลายกรณี reCAPTCHA จะแก้ปัญหาเองโดยอัตโนมัติโดยที่ผู้ใช้ไม่ต้องดำเนินการใดๆ
การใช้การแจ้งเตือนแบบเงียบ
หากต้องการเปิดใช้งานการแจ้งเตือน APN เพื่อใช้กับ Firebase:
ใน Xcode ให้เปิดใช้งานการแจ้งเตือนแบบพุช สำหรับโปรเจ็กต์ของคุณ
อัปโหลดคีย์การตรวจสอบสิทธิ์ APN ของคุณโดยใช้คอนโซล Firebase (การเปลี่ยนแปลงของคุณจะถูกส่งต่อไปยัง Google Cloud Firebase โดยอัตโนมัติ) หากคุณยังไม่มีคีย์การตรวจสอบสิทธิ์ APN โปรดดู การกำหนดค่า APN ด้วย FCM เพื่อเรียนรู้วิธีการรับ
เปิด คอนโซล Firebase
นำทางไปยัง การตั้งค่าโครงการ
เลือกแท็บ การส่งข้อความบนคลาวด์
ใต้ คีย์การตรวจสอบสิทธิ์ APN ในส่วน การกำหนดค่าแอป iOS ให้คลิก อัปโหลด
เลือกรหัสของคุณ
เพิ่มรหัสคีย์สำหรับคีย์ คุณสามารถค้นหารหัสคีย์ได้ในส่วน ใบรับรอง ตัวระบุ และโปรไฟล์ ใน ศูนย์นักพัฒนา Apple
คลิก อัปโหลด
หากคุณมีใบรับรอง APN อยู่แล้ว คุณสามารถอัปโหลดใบรับรองแทนได้
ใช้การยืนยัน reCAPTCHA
หากต้องการเปิดใช้งาน SDK ไคลเอ็นต์เพื่อใช้ reCAPTCHA:
เปิดการกำหนดค่าโครงการของคุณใน Xcode
ดับเบิลคลิกชื่อโครงการในมุมมองแผนผังด้านซ้าย
เลือกแอปของคุณจากส่วน เป้าหมาย
เลือกแท็บ ข้อมูล
ขยายส่วน ประเภท URL
คลิกปุ่ม +
ป้อนรหัสไคลเอ็นต์ที่กลับรายการของคุณในฟิลด์ แบบแผน URL คุณจะพบค่านี้ที่แสดงอยู่ในไฟล์การกำหนดค่า
GoogleService-Info.plist
เป็นREVERSED_CLIENT_ID
เมื่อเสร็จแล้ว การกำหนดค่าของคุณควรมีลักษณะคล้ายกับต่อไปนี้:
หรือคุณสามารถปรับแต่งวิธีที่แอปนำเสนอ SFSafariViewController
หรือ UIWebView
เมื่อแสดง reCAPTCHA ได้ เมื่อต้องการทำเช่นนี้ ให้สร้างคลาสแบบกำหนดเองที่สอดคล้องกับโปรโตคอล FIRAuthUIDelegate
และส่งผ่านไปยัง verifyPhoneNumber:UIDelegate:completion:
การเลือกรูปแบบการลงทะเบียน
คุณสามารถเลือกได้ว่าแอปของคุณต้องมีการตรวจสอบสิทธิ์แบบหลายปัจจัยหรือไม่ รวมถึงจะลงทะเบียนผู้ใช้อย่างไรและเมื่อใด รูปแบบทั่วไปบางประการ ได้แก่:
ลงทะเบียนปัจจัยที่สองของผู้ใช้เป็นส่วนหนึ่งของการลงทะเบียน ใช้วิธีนี้หากแอปของคุณต้องมีการตรวจสอบสิทธิ์แบบหลายปัจจัยสำหรับผู้ใช้ทั้งหมด โปรดทราบว่าบัญชีต้องมีที่อยู่อีเมลที่ยืนยันแล้วจึงจะลงทะเบียนปัจจัยที่สองได้ ดังนั้นขั้นตอนการลงทะเบียนของคุณจะต้องรองรับสิ่งนี้
เสนอตัวเลือกที่ข้ามได้เพื่อลงทะเบียนปัจจัยที่ 2 ระหว่างการลงทะเบียน แอพที่ต้องการสนับสนุน แต่ไม่จำเป็นต้องมีการตรวจสอบสิทธิ์แบบหลายปัจจัยอาจชอบวิธีนี้
ให้ความสามารถในการเพิ่มปัจจัยที่สองจากบัญชีของผู้ใช้หรือหน้าการจัดการโปรไฟล์ แทนหน้าจอการลงทะเบียน สิ่งนี้จะช่วยลดความขัดแย้งระหว่างขั้นตอนการลงทะเบียน ในขณะที่ยังคงให้การรับรองความถูกต้องแบบหลายปัจจัยสำหรับผู้ใช้ที่คำนึงถึงความปลอดภัย
ต้องเพิ่มปัจจัยที่สองทีละน้อยเมื่อผู้ใช้ต้องการเข้าถึงคุณลักษณะที่มีข้อกำหนดด้านความปลอดภัยที่เพิ่มขึ้น
การลงทะเบียนปัจจัยที่สอง
หากต้องการลงทะเบียนปัจจัยรองใหม่สำหรับผู้ใช้:
ตรวจสอบสิทธิ์ผู้ใช้อีกครั้ง
ขอให้ผู้ใช้ป้อนหมายเลขโทรศัพท์ของตน
รับเซสชันแบบหลายปัจจัยสำหรับผู้ใช้:
สวิฟท์
authResult.user.multiFactor.getSessionWithCompletion() { (session, error) in // ... }
วัตถุประสงค์-C
[authResult.user.multiFactor getSessionWithCompletion:^(FIRMultiFactorSession * _Nullable session, NSError * _Nullable error) { // ... }];
ส่งข้อความยืนยันไปยังโทรศัพท์ของผู้ใช้ ตรวจสอบให้แน่ใจว่าหมายเลขโทรศัพท์อยู่ในรูปแบบที่มีเครื่องหมาย
+
นำหน้า และไม่มีเครื่องหมายวรรคตอนหรือช่องว่างอื่นๆ (เช่น+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. }];
แม้ว่าจะไม่จำเป็น แต่แนวทางปฏิบัติที่ดีที่สุดคือแจ้งให้ผู้ใช้ทราบล่วงหน้าว่าพวกเขาจะได้รับข้อความ SMS และใช้อัตรามาตรฐานดังกล่าว
เมธอด
verifyPhoneNumber()
เริ่มกระบวนการตรวจสอบแอปในเบื้องหลังโดยใช้การแจ้งเตือนแบบพุชแบบเงียบ หากไม่มีการแจ้งเตือนแบบพุช ระบบจะออกคำถาม reCAPTCHA แทนเมื่อส่งรหัส SMS แล้ว ขอให้ผู้ใช้ยืนยันรหัส จากนั้นใช้การตอบสนองเพื่อสร้าง
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];
เริ่มต้นวัตถุการยืนยัน:
สวิฟท์
let assertion = PhoneMultiFactorGenerator.assertion(with: credential)
วัตถุประสงค์-C
FIRMultiFactorAssertion *assertion = [FIRPhoneMultiFactorGenerator assertionWithCredential:credential];
เสร็จสิ้นการลงทะเบียน หรือคุณสามารถระบุชื่อที่แสดงสำหรับปัจจัยที่สองได้ สิ่งนี้มีประโยชน์สำหรับผู้ใช้ที่มีปัจจัยวินาทีหลายตัว เนื่องจากหมายเลขโทรศัพท์ถูกปกปิดในระหว่างขั้นตอนการตรวจสอบสิทธิ์ (เช่น +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 // ... }
วัตถุประสงค์-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) {
// ...
}];
}];
}];
ยินดีด้วย! คุณลงทะเบียนปัจจัยการรับรองความถูกต้องที่สองสำหรับผู้ใช้สำเร็จแล้ว
การลงชื่อเข้าใช้ผู้ใช้ด้วยปัจจัยที่ 2
หากต้องการลงชื่อเข้าใช้ผู้ใช้ด้วยการยืนยัน SMS แบบสองปัจจัย:
ลงชื่อเข้าใช้ผู้ใช้ด้วยปัจจัยแรก จากนั้นตรวจพบข้อผิดพลาดที่ระบุว่าจำเป็นต้องมีการตรวจสอบสิทธิ์แบบหลายปัจจัย ข้อผิดพลาดนี้มีตัวแก้ไข คำแนะนำเกี่ยวกับปัจจัยที่สองที่ลงทะเบียน และเซสชันพื้นฐานที่พิสูจน์ว่าผู้ใช้ตรวจสอบสิทธิ์ด้วยปัจจัยแรกได้สำเร็จ
ตัวอย่างเช่น หากปัจจัยแรกของผู้ใช้คืออีเมลและรหัสผ่าน:
สวิฟท์
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()
หากผู้ใช้มีปัจจัยรองหลายรายการที่ลงทะเบียนไว้ ให้ถามผู้ใช้ว่าควรใช้ปัจจัยใด คุณสามารถรับหมายเลขโทรศัพท์ที่มาสก์ได้ด้วย
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. }
ส่งข้อความยืนยันไปยังโทรศัพท์ของผู้ใช้:
สวิฟท์
// 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. } }];
เมื่อส่งรหัส SMS แล้ว ขอให้ผู้ใช้ตรวจสอบรหัสและใช้เพื่อสร้าง
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];
เริ่มต้นวัตถุยืนยันด้วยหนังสือรับรอง:
สวิฟท์
let assertion = PhoneMultiFactorGenerator.assertion(with: credential)
วัตถุประสงค์-C
FIRMultiFactorAssertion *assertion = [FIRPhoneMultiFactorGenerator assertionWithCredential:credential];
แก้ไขปัญหาการลงชื่อเข้าใช้ จากนั้นคุณจึงสามารถเข้าถึงผลการลงชื่อเข้าใช้เดิมได้ ซึ่งรวมถึงข้อมูลเฉพาะของผู้ให้บริการมาตรฐานและข้อมูลประจำตัวการตรวจสอบสิทธิ์:
สวิฟท์
// 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.
}
}];
}];
}
}];
ยินดีด้วย! คุณลงชื่อเข้าใช้ผู้ใช้โดยใช้การรับรองความถูกต้องแบบหลายปัจจัยสำเร็จแล้ว
อะไรต่อไป
- จัดการผู้ใช้แบบหลายปัจจัย โดยทางโปรแกรมด้วย Admin SDK