ตรวจสอบสิทธิ์โดยใช้ Apple บน Android

คุณอนุญาตให้ผู้ใช้ตรวจสอบสิทธิ์กับ Firebase โดยใช้ Apple ID ได้โดยใช้ Firebase SDK เพื่อดำเนินการขั้นตอนการลงชื่อเข้าใช้ OAuth 2.0 ตั้งแต่ต้นทางถึงปลายทาง

ก่อนจะเริ่ม

ในการลงชื่อเข้าใช้ผู้ใช้โดยใช้ Apple ก่อนอื่นให้กำหนดค่าการลงชื่อเข้าใช้ด้วย Apple บนเว็บไซต์นักพัฒนาของ Apple จากนั้นเปิดใช้งาน Apple เป็นผู้ให้บริการการลงชื่อเข้าใช้สำหรับโปรเจ็กต์ Firebase ของคุณ

เข้าร่วม Apple Developer Program

การลงชื่อเข้าใช้ด้วย Apple สามารถกำหนดค่าได้โดยสมาชิกของ Apple Developer Program เท่านั้น

กำหนดค่าการลงชื่อเข้าใช้ด้วย Apple

บนไซต์ Apple Developer ให้ทำดังต่อไปนี้:

  1. เชื่อมโยงเว็บไซต์ของคุณกับแอพของคุณตามที่อธิบายไว้ในส่วนแรกของ กำหนดค่าการลงชื่อเข้าใช้ด้วย Apple สำหรับเว็บ เมื่อได้รับแจ้ง ให้ลงทะเบียน URL ต่อไปนี้เป็น Return URL:

    https://YOUR_FIREBASE_PROJECT_ID.firebaseapp.com/__/auth/handler

    คุณสามารถรับรหัสโปรเจ็กต์ Firebase ได้ใน หน้าการตั้งค่าคอนโซล Firebase

    เมื่อเสร็จแล้ว ให้จดรหัสบริการใหม่ของคุณ ซึ่งคุณจะต้องใช้ในส่วนถัดไป

  2. สร้างการลงชื่อเข้าใช้ด้วยคีย์ส่วนตัวของ Apple คุณจะต้องใช้คีย์ส่วนตัวและรหัสคีย์ใหม่ในส่วนถัดไป
  3. หากคุณใช้คุณลักษณะของ Firebase Authentication ที่ส่งอีเมลถึงผู้ใช้ รวมถึงการลงชื่อเข้าใช้ลิงก์อีเมล การยืนยันที่อยู่อีเมล การเพิกถอนการเปลี่ยนแปลงบัญชี และอื่นๆ ให้ กำหนดค่าบริการส่งต่ออีเมลส่วนตัวของ Apple และลงทะเบียน noreply@ YOUR_FIREBASE_PROJECT_ID .firebaseapp.com (หรือ โดเมนเทมเพลตอีเมลที่คุณกำหนดเอง) เพื่อให้ Apple สามารถส่งต่ออีเมลที่ส่งโดยการตรวจสอบสิทธิ์ Firebase ไปยังที่อยู่อีเมล Apple ที่ไม่ระบุตัวตน

เปิดใช้งาน Apple เป็นผู้ให้บริการลงชื่อเข้าใช้

  1. เพิ่ม Firebase ในโครงการ Android ของคุณ อย่าลืมลงทะเบียนลายเซ็น SHA-1 ของแอปเมื่อคุณตั้งค่าแอปในคอนโซล Firebase
  2. ใน คอนโซล Firebase ให้เปิดส่วนการ ตรวจสอบสิทธิ์ บนแท็บ วิธีการลงชื่อเข้า ใช้ ให้เปิดใช้งานผู้ให้บริการ Apple ระบุรหัสบริการที่คุณสร้างขึ้นในส่วนก่อนหน้า นอกจากนี้ ในส่วน การกำหนดค่าโฟลว์โค้ด OAuth ให้ ระบุ Apple Team ID และคีย์ส่วนตัวและ ID คีย์ที่คุณสร้างขึ้นในส่วนก่อนหน้า

ปฏิบัติตามข้อกำหนดด้านข้อมูลที่ไม่ระบุตัวตนของ Apple

ลงชื่อเข้าใช้ด้วย Apple ให้ผู้ใช้มีตัวเลือกในการปกปิดข้อมูล รวมถึงที่อยู่อีเมล เมื่อลงชื่อเข้าใช้ ผู้ใช้ที่เลือกตัวเลือกนี้มีที่อยู่อีเมลที่มีโดเมน privaterelay.appleid.com เมื่อคุณใช้ลงชื่อเข้าด้วย Apple ในแอปของคุณ คุณต้องปฏิบัติตามนโยบายหรือข้อกำหนดของนักพัฒนาที่เกี่ยวข้องใดๆ จาก Apple เกี่ยวกับ Apple ID ที่ไม่ระบุชื่อเหล่านี้

ซึ่งรวมถึงการขอความยินยอมจากผู้ใช้ที่จำเป็นก่อนที่คุณจะเชื่อมโยงข้อมูลส่วนบุคคลที่ระบุตัวตนโดยตรงใดๆ กับ Apple ID ที่ไม่ระบุตัวตน เมื่อใช้การตรวจสอบสิทธิ์ Firebase อาจรวมถึงการดำเนินการต่อไปนี้:

  • เชื่อมโยงที่อยู่อีเมลกับ Apple ID ที่ไม่ระบุตัวตนหรือในทางกลับกัน
  • เชื่อมโยงหมายเลขโทรศัพท์กับ Apple ID ที่ไม่ระบุตัวตนหรือในทางกลับกัน
  • เชื่อมโยงข้อมูลประจำตัวทางสังคมที่ไม่ระบุชื่อ (Facebook, Google ฯลฯ) กับ Apple ID ที่ไม่ระบุตัวตนหรือในทางกลับกัน

รายการข้างต้นไม่ครบถ้วนสมบูรณ์ โปรดดูข้อตกลงสิทธิ์การใช้งานโปรแกรมนักพัฒนาซอฟต์แวร์ของ Apple ในส่วนการเป็นสมาชิกของบัญชีนักพัฒนาซอฟต์แวร์ของคุณ เพื่อให้แน่ใจว่าแอปของคุณตรงตามข้อกำหนดของ Apple

จัดการขั้นตอนการลงชื่อเข้าใช้ด้วย Firebase SDK

ใน Android วิธีที่ง่ายที่สุดในการตรวจสอบสิทธิ์ผู้ใช้ของคุณด้วย Firebase โดยใช้บัญชี Apple คือการจัดการขั้นตอนการลงชื่อเข้าใช้ทั้งหมดด้วย Firebase Android SDK

ในการจัดการขั้นตอนการลงชื่อเข้าใช้ด้วย Firebase Android SDK ให้ทำตามขั้นตอนเหล่านี้:

  1. สร้างอินสแตนซ์ของ OAuthProvider โดยใช้ตัวสร้างด้วย ID ผู้ให้บริการ apple.com :

    Java

    OAuthProvider.Builder provider = OAuthProvider.newBuilder("apple.com");
    

    Kotlin+KTX

    val provider = OAuthProvider.newBuilder("apple.com")
    
  2. ไม่บังคับ: ระบุขอบเขต OAuth 2.0 เพิ่มเติมนอกเหนือจากค่าเริ่มต้นที่คุณต้องการขอจากผู้ให้บริการตรวจสอบสิทธิ์

    Java

    List<String> scopes =
        new ArrayList<String>() {
          {
            add("email");
            add("name");
          }
        };
    provider.setScopes(scopes);
    

    Kotlin+KTX

    provider.setScopes(arrayOf("email", "name"))
    

    โดยค่าเริ่มต้น เมื่อเปิดใช้ หนึ่งบัญชีต่อที่อยู่อีเมล Firebase จะขอขอบเขตอีเมลและชื่อ หากคุณเปลี่ยนการตั้งค่านี้เป็น หลายบัญชีต่อที่อยู่อีเมล Firebase จะไม่ขอขอบเขตใดๆ จาก Apple เว้นแต่คุณจะระบุไว้

  3. ไม่บังคับ: หากคุณต้องการแสดงหน้าจอลงชื่อเข้าใช้ของ Apple ในภาษาอื่นที่ไม่ใช่ภาษาอังกฤษ ให้ตั้งค่าพารามิเตอร์ locale ดูเอกสารการ ลงชื่อเข้าใช้ด้วย Apple สำหรับภาษาที่รองรับ

    Java

    // Localize the Apple authentication screen in French.
    provider.addCustomParameter("locale", "fr");
    

    Kotlin+KTX

    // Localize the Apple authentication screen in French.
    provider.addCustomParameter("locale", "fr")
    
  4. ตรวจสอบสิทธิ์กับ Firebase โดยใช้วัตถุผู้ให้บริการ OAuth โปรดทราบว่าการดำเนินการนี้จะควบคุม UI ของคุณโดยเปิดแท็บ Chrome ที่กำหนดเอง ซึ่งไม่เหมือนกับการดำเนินการ FirebaseAuth อื่นๆ ดังนั้น อย่าอ้างอิงกิจกรรมของคุณใน OnSuccessListener และ OnFailureListener ที่คุณแนบ เนื่องจากจะแยกออกทันทีเมื่อการดำเนินการเริ่ม UI

    คุณควรตรวจสอบก่อนว่าคุณได้รับคำตอบแล้วหรือไม่ การลงชื่อเข้าใช้ด้วยวิธีนี้จะทำให้กิจกรรมของคุณอยู่ในพื้นหลัง ซึ่งหมายความว่าระบบสามารถเรียกคืนได้ในระหว่างการลงชื่อเข้าใช้ เพื่อให้แน่ใจว่าคุณจะไม่ให้ผู้ใช้ลองอีกครั้งหากเกิดเหตุการณ์นี้ขึ้น คุณควรตรวจสอบว่ามีผลลัพธ์อยู่แล้วหรือไม่

    หากต้องการตรวจสอบว่ามีผลลัพธ์ที่รอดำเนินการหรือไม่ ให้โทร getPendingAuthResult() :

    Java

    mAuth = FirebaseAuth.getInstance();
    Task<AuthResult> pending = mAuth.getPendingAuthResult();
    if (pending != null) {
        pending.addOnSuccessListener(new OnSuccessListener<AuthResult>() {
            @Override
            public void onSuccess(AuthResult authResult) {
                Log.d(TAG, "checkPending:onSuccess:" + authResult);
                // Get the user profile with authResult.getUser() and
                // authResult.getAdditionalUserInfo(), and the ID
                // token from Apple with authResult.getCredential().
            }
        }).addOnFailureListener(new OnFailureListener() {
            @Override
            public void onFailure(@NonNull Exception e) {
                Log.w(TAG, "checkPending:onFailure", e);
            }
        });
    } else {
        Log.d(TAG, "pending: null");
    }
    

    Kotlin+KTX

    val pending = auth.pendingAuthResult
    if (pending != null) {
        pending.addOnSuccessListener { authResult ->
            Log.d(TAG, "checkPending:onSuccess:$authResult")
            // Get the user profile with authResult.getUser() and
            // authResult.getAdditionalUserInfo(), and the ID
            // token from Apple with authResult.getCredential().
        }.addOnFailureListener { e ->
            Log.w(TAG, "checkPending:onFailure", e)
        }
    } else {
        Log.d(TAG, "pending: null")
    }
    

    หากไม่มีผลลัพธ์ที่รอดำเนินการ ให้เริ่มขั้นตอนการลงชื่อเข้าใช้โดยเรียก startActivityForSignInWithProvider() :

    Java

    mAuth.startActivityForSignInWithProvider(this, provider.build())
            .addOnSuccessListener(
                    new OnSuccessListener<AuthResult>() {
                        @Override
                        public void onSuccess(AuthResult authResult) {
                            // Sign-in successful!
                            Log.d(TAG, "activitySignIn:onSuccess:" + authResult.getUser());
                            FirebaseUser user = authResult.getUser();
                            // ...
                        }
                    })
            .addOnFailureListener(
                    new OnFailureListener() {
                        @Override
                        public void onFailure(@NonNull Exception e) {
                            Log.w(TAG, "activitySignIn:onFailure", e);
                        }
                    });
    

    Kotlin+KTX

    auth.startActivityForSignInWithProvider(this, provider.build())
            .addOnSuccessListener { authResult ->
                // Sign-in successful!
                Log.d(TAG, "activitySignIn:onSuccess:${authResult.user}")
                val user = authResult.user
                // ...
            }
            .addOnFailureListener { e ->
                Log.w(TAG, "activitySignIn:onFailure", e)
            }
    

    ไม่เหมือนกับผู้ให้บริการรายอื่นที่สนับสนุนโดย Firebase Auth Apple ไม่มี URL รูปภาพ

    นอกจากนี้ เมื่อผู้ใช้เลือกที่จะไม่แชร์อีเมลกับแอป Apple จะจัดเตรียมที่อยู่อีเมลเฉพาะสำหรับผู้ใช้รายนั้น (ในรูปแบบ xyz@privaterelay.appleid.com ) ซึ่งจะแชร์กับแอปของคุณ หากคุณกำหนดค่าบริการส่งต่ออีเมลส่วนตัว Apple จะส่งต่ออีเมลที่ส่งไปยังที่อยู่ที่ไม่ระบุชื่อไปยังที่อยู่อีเมลจริงของผู้ใช้

    Apple แชร์เฉพาะข้อมูลผู้ใช้ เช่น ชื่อที่แสดงกับแอพในครั้งแรกที่ผู้ใช้ลงชื่อเข้าใช้ โดยปกติ Firebase จะจัดเก็บชื่อที่แสดงในครั้งแรกที่ผู้ใช้ลงชื่อเข้าใช้ Apple ซึ่งคุณจะได้รับด้วย getCurrentUser().getDisplayName() อย่างไรก็ตาม หากคุณเคยใช้ Apple เพื่อลงชื่อเข้าใช้แอปให้ผู้ใช้โดยไม่ใช้ Firebase Apple จะไม่ให้ชื่อที่แสดงของผู้ใช้กับ Firebase

การตรวจสอบสิทธิ์ซ้ำและการเชื่อมโยงบัญชี

สามารถใช้รูปแบบเดียวกันกับ startActivityForReauthenticateWithProvider() ซึ่งคุณสามารถใช้เพื่อดึงข้อมูลรับรองใหม่สำหรับการดำเนินการที่มีความละเอียดอ่อนซึ่งจำเป็นต้องมีการลงชื่อเข้าใช้ล่าสุด:

Java

// The user is already signed-in.
FirebaseUser firebaseUser = mAuth.getCurrentUser();

firebaseUser
    .startActivityForReauthenticateWithProvider(/* activity= */ this, provider.build())
    .addOnSuccessListener(
        new OnSuccessListener<AuthResult>() {
          @Override
          public void onSuccess(AuthResult authResult) {
            // User is re-authenticated with fresh tokens and
            // should be able to perform sensitive operations
            // like account deletion and email or password
            // update.
          }
        })
    .addOnFailureListener(
        new OnFailureListener() {
          @Override
          public void onFailure(@NonNull Exception e) {
            // Handle failure.
          }
        });

Kotlin+KTX

// The user is already signed-in.
val firebaseUser = auth.getCurrentUser()

firebaseUser
    .startActivityForReauthenticateWithProvider(/* activity= */ this, provider.build())
    .addOnSuccessListener( authResult -> {
        // User is re-authenticated with fresh tokens and
        // should be able to perform sensitive operations
        // like account deletion and email or password
        // update.
    })
    .addOnFailureListener( e -> {
        // Handle failure.
    })

และคุณสามารถใช้ linkWithCredential() เพื่อเชื่อมโยงผู้ให้บริการข้อมูลประจำตัวต่างๆ กับบัญชีที่มีอยู่

โปรดทราบว่า Apple กำหนดให้คุณต้องได้รับความยินยอมอย่างชัดแจ้งจากผู้ใช้ก่อนที่จะเชื่อมโยงบัญชี Apple กับข้อมูลอื่น

ตัวอย่างเช่น ในการเชื่อมโยงบัญชี Facebook กับบัญชี Firebase ปัจจุบัน ให้ใช้โทเค็นการเข้าถึงที่คุณได้รับจากการลงชื่อเข้าใช้ Facebook:

Java

// Initialize a Facebook credential with a Facebook access token.
AuthCredential credential = FacebookAuthProvider.getCredential(token.getToken());

// Assuming the current user is an Apple user linking a Facebook provider.
mAuth.getCurrentUser().linkWithCredential(credential)
    .addOnCompleteListener(this, new OnCompleteListener<AuthResult>() {
      @Override
      public void onComplete(@NonNull Task<AuthResult> task) {
        if (task.isSuccessful()) {
          // Facebook credential is linked to the current Apple user.
          // The user can now sign in to the same account
          // with either Apple or Facebook.
        }
      }
    });

Kotlin+KTX

// Initialize a Facebook credential with a Facebook access token.
val credential = FacebookAuthProvider.getCredential(token.getToken())

// Assuming the current user is an Apple user linking a Facebook provider.
mAuth.getCurrentUser().linkWithCredential(credential)
    .addOnCompleteListener(this, task -> {
        if (task.isSuccessful()) {
          // Facebook credential is linked to the current Apple user.
          // The user can now sign in to the same account
          // with either Apple or Facebook.
        }
      });

ขั้นสูง: จัดการขั้นตอนการลงชื่อเข้าใช้ด้วยตนเอง

คุณยังสามารถตรวจสอบสิทธิ์กับ Firebase โดยใช้บัญชี Apple โดยจัดการขั้นตอนการลงชื่อเข้าใช้โดยใช้ Apple Sign-In JS SDK สร้างขั้นตอน OAuth ด้วยตนเอง หรือโดยใช้ไลบรารี OAuth เช่น AppAuth

  1. สำหรับคำขอลงชื่อเข้าใช้ทุกครั้ง ให้สร้างสตริงสุ่ม ซึ่งก็คือ "nonce" ซึ่งคุณจะใช้เพื่อให้แน่ใจว่าโทเค็น ID ที่คุณได้รับนั้นได้รับการอนุญาตเป็นการเฉพาะเพื่อตอบสนองต่อคำขอตรวจสอบสิทธิ์ของแอปของคุณ ขั้นตอนนี้มีความสำคัญต่อการป้องกันการโจมตีซ้ำ

    คุณสามารถสร้าง nonce ที่ปลอดภัยในการเข้ารหัสบน Android ด้วย SecureRandom ดังในตัวอย่างต่อไปนี้:

    Java

    private String generateNonce(int length) {
        SecureRandom generator = new SecureRandom();
    
        CharsetDecoder charsetDecoder = StandardCharsets.US_ASCII.newDecoder();
        charsetDecoder.onUnmappableCharacter(CodingErrorAction.IGNORE);
        charsetDecoder.onMalformedInput(CodingErrorAction.IGNORE);
    
        byte[] bytes = new byte[length];
        ByteBuffer inBuffer = ByteBuffer.wrap(bytes);
        CharBuffer outBuffer = CharBuffer.allocate(length);
        while (outBuffer.hasRemaining()) {
            generator.nextBytes(bytes);
            inBuffer.rewind();
            charsetDecoder.reset();
            charsetDecoder.decode(inBuffer, outBuffer, false);
        }
        outBuffer.flip();
        return outBuffer.toString();
    }
    

    Kotlin+KTX

    private fun generateNonce(length: Int): String {
        val generator = SecureRandom()
    
        val charsetDecoder = StandardCharsets.US_ASCII.newDecoder()
        charsetDecoder.onUnmappableCharacter(CodingErrorAction.IGNORE)
        charsetDecoder.onMalformedInput(CodingErrorAction.IGNORE)
    
        val bytes = ByteArray(length)
        val inBuffer = ByteBuffer.wrap(bytes)
        val outBuffer = CharBuffer.allocate(length)
        while (outBuffer.hasRemaining()) {
            generator.nextBytes(bytes)
            inBuffer.rewind()
            charsetDecoder.reset()
            charsetDecoder.decode(inBuffer, outBuffer, false)
        }
        outBuffer.flip()
        return outBuffer.toString()
    }
    

    จากนั้น รับแฮช SHA246 ของ nonce เป็นสตริงฐานสิบหก:

    Java

    private String sha256(String s) throws NoSuchAlgorithmException {
        MessageDigest md = MessageDigest.getInstance("SHA-256");
        byte[] digest = md.digest(s.getBytes());
        StringBuilder hash = new StringBuilder();
        for (byte c: digest) {
            hash.append(String.format("%02x", c));
        }
        return hash.toString();
    }
    

    Kotlin+KTX

    private fun sha256(s: String): String {
        val md = MessageDigest.getInstance("SHA-256")
        val digest = md.digest(s.toByteArray())
        val hash = StringBuilder()
        for (c in digest) {
            hash.append(String.format("%02x", c))
        }
        return hash.toString()
    }
    

    คุณจะส่งแฮช SHA256 ของ nonce ไปพร้อมกับคำขอลงชื่อเข้าใช้ของคุณ ซึ่ง Apple จะไม่เปลี่ยนคำตอบในการตอบกลับ Firebase ตรวจสอบการตอบสนองโดยแฮช nonce ดั้งเดิมและเปรียบเทียบกับค่าที่ Apple ส่งผ่าน

  2. เริ่มขั้นตอนการลงชื่อเข้าใช้ของ Apple โดยใช้ไลบรารี OAuth หรือวิธีอื่นๆ อย่าลืมรวม nonce ที่แฮชเป็นพารามิเตอร์ในคำขอของคุณ

  3. หลังจากที่คุณได้รับการตอบสนองของ Apple ให้รับโทเค็น ID จากการตอบกลับและใช้งานและ nonce ที่ไม่ได้แฮชเพื่อสร้าง AuthCredential :

    Java

    AuthCredential credential =  OAuthProvider.newCredentialBuilder("apple.com")
        .setIdTokenWithRawNonce(appleIdToken, rawUnhashedNonce)
        .build();
    

    Kotlin+KTX

    val credential =  OAuthProvider.newCredentialBuilder("apple.com")
        .setIdTokenWithRawNonce(appleIdToken, rawUnhashedNonce)
        .build()
    
  4. ตรวจสอบสิทธิ์กับ Firebase โดยใช้ข้อมูลรับรอง Firebase:

    Java

    mAuth.signInWithCredential(credential)
        .addOnCompleteListener(this, new OnCompleteListener<AuthResult>() {
          @Override
          public void onComplete(@NonNull Task<AuthResult> task) {
            if (task.isSuccessful()) {
              // User successfully signed in with Apple ID token.
              // ...
            }
          }
        });
    

    Kotlin+KTX

    auth.signInWithCredential(credential)
          .addOnCompleteListener(this) { task ->
              if (task.isSuccessful) {
                // User successfully signed in with Apple ID token.
                // ...
              }
          }
    

หากการเรียก signInWithCredential สำเร็จ คุณสามารถใช้เมธอด getCurrentUser เพื่อรับข้อมูลบัญชีผู้ใช้

ขั้นตอนถัดไป

หลังจากที่ผู้ใช้ลงชื่อเข้าใช้เป็นครั้งแรก บัญชีผู้ใช้ใหม่จะถูกสร้างขึ้นและเชื่อมโยงกับข้อมูลประจำตัว นั่นคือ ชื่อผู้ใช้และรหัสผ่าน หมายเลขโทรศัพท์ หรือข้อมูลผู้ให้บริการตรวจสอบสิทธิ์ ซึ่งผู้ใช้ลงชื่อเข้าใช้ บัญชีใหม่นี้จัดเก็บเป็นส่วนหนึ่งของโปรเจ็กต์ Firebase และใช้เพื่อระบุผู้ใช้ในทุกแอปในโปรเจ็กต์ของคุณ ไม่ว่าผู้ใช้จะลงชื่อเข้าใช้ด้วยวิธีใดก็ตาม

  • ในแอปของคุณ คุณสามารถรับข้อมูลโปรไฟล์พื้นฐานของผู้ใช้จากอ็อบเจ็กต์ FirebaseUser ดู จัดการผู้ใช้

  • ในฐานข้อมูล Firebase Realtime Database และ Cloud Storage Security Rules คุณสามารถรับ ID ผู้ใช้เฉพาะของผู้ใช้ที่ลงชื่อเข้าใช้จากตัวแปร auth และใช้เพื่อควบคุมข้อมูลที่ผู้ใช้สามารถเข้าถึงได้

คุณสามารถอนุญาตให้ผู้ใช้ลงชื่อเข้าใช้แอปของคุณโดยใช้ผู้ให้บริการตรวจสอบสิทธิ์หลายรายโดย เชื่อมโยงข้อมูลรับรองของผู้ให้บริการตรวจสอบสิทธิ์กับบัญชีผู้ใช้ที่มีอยู่

หากต้องการออกจากระบบผู้ใช้ โทร signOut :

Java

FirebaseAuth.getInstance().signOut();

Kotlin+KTX

Firebase.auth.signOut()