Join us for Firebase Summit on November 10, 2021. Tune in to learn how Firebase can help you accelerate app development, release with confidence, and scale with ease. Register

Xác thực bằng Apple trên Android

Bạn có thể cho phép người dùng của mình xác thực với Firebase bằng ID Apple của họ bằng cách sử dụng SDK Firebase để thực hiện quy trình đăng nhập OAuth 2.0 end-to-end.

Trước khi bắt đầu

Để đăng nhập người dùng bằng Apple, trước tiên hãy định cấu hình Đăng nhập với Apple trên trang web dành cho nhà phát triển của Apple, sau đó bật Apple làm nhà cung cấp dịch vụ đăng nhập cho dự án Firebase của bạn.

Tham gia chương trình nhà phát triển Apple

Đăng nhập với Apple chỉ có thể được cấu hình bởi các thành viên của Apple phát triển chương trình .

Định cấu hình Đăng nhập với Apple

Trên Apple phát triển trang web, làm như sau:

  1. Liên kết trang web của bạn để ứng dụng của bạn như được mô tả trong phần đầu tiên của Configure Đăng nhập với Apple cho web . Khi được nhắc, hãy đăng ký URL sau làm URL trả lại:

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

    Bạn có thể lấy ID dự án căn cứ hỏa lực của bạn trên trang căn cứ hỏa lực console thiết lập .

    Khi bạn hoàn tất, hãy ghi lại ID dịch vụ mới của bạn, ID này bạn sẽ cần trong phần tiếp theo.

  2. Tạo Trong Sign với khóa riêng của Apple . Bạn sẽ cần khóa riêng tư mới và ID khóa trong phần tiếp theo.
  3. Nếu bạn sử dụng bất kỳ tính năng căn cứ hỏa lực xác thực của email tới người dùng, bao gồm cả liên kết email đăng nhập, xác minh địa chỉ email, thay đổi tài khoản thu hồi, và những người khác, cấu hình các dịch vụ chuyển tiếp email cá nhân của Apple và đăng ký noreply@ YOUR_FIREBASE_PROJECT_ID .firebaseapp.com (hoặc miền mẫu email tùy chỉnh của bạn) để Apple có thể chuyển tiếp các email do Xác thực Firebase gửi đến các địa chỉ email Apple ẩn danh.

Cho phép Apple làm nhà cung cấp dịch vụ đăng nhập

  1. Thêm căn cứ hỏa lực cho dự án Android của bạn . Đảm bảo đăng ký chữ ký SHA-1 của ứng dụng khi bạn thiết lập ứng dụng của mình trong bảng điều khiển Firebase.
  2. Trong căn cứ hỏa lực console , hãy mở phần Auth. Trên Đăng nhập tab phương pháp, cho phép các nhà cung cấp của Apple. Chỉ định ID dịch vụ bạn đã tạo trong phần trước. Ngoài ra, trong phần cấu hình dòng mã OAuth, chỉ định của Apple Đội ID của bạn và khóa bí mật và ID chìa khóa mà bạn đã tạo trong phần trước.

Tuân thủ các yêu cầu về dữ liệu ẩn danh của Apple

Đăng nhập với Apple cung cấp cho người dùng tùy chọn của nặc danh hóa dữ liệu của họ, bao gồm địa chỉ email của họ, khi đăng nhập. Người dùng chọn tùy chọn này có địa chỉ email với các tên miền privaterelay.appleid.com . Khi bạn sử dụng Đăng nhập bằng Apple trong ứng dụng của mình, bạn phải tuân thủ mọi chính sách hoặc điều khoản hiện hành dành cho nhà phát triển từ Apple về các ID Apple ẩn danh này.

Điều này bao gồm việc nhận được bất kỳ sự đồng ý cần thiết nào của người dùng trước khi bạn liên kết bất kỳ thông tin cá nhân nhận dạng trực tiếp nào với ID Apple ẩn danh. Khi sử dụng Xác thực Firebase, điều này có thể bao gồm các hành động sau:

  • Liên kết địa chỉ email với ID Apple ẩn danh hoặc ngược lại.
  • Liên kết số điện thoại với ID Apple ẩn danh hoặc ngược lại
  • Liên kết thông tin đăng nhập xã hội không ẩn danh (Facebook, Google, v.v.) với ID Apple ẩn danh hoặc ngược lại.

Danh sách trên không toàn diện. Tham khảo Thỏa thuận cấp phép chương trình nhà phát triển của Apple trong phần Tư cách thành viên của tài khoản nhà phát triển của bạn để đảm bảo ứng dụng của bạn đáp ứng các yêu cầu của Apple.

Xử lý quy trình đăng nhập với SDK Firebase

Trên Android, cách dễ nhất để xác thực người dùng của bạn với Firebase bằng tài khoản Apple của họ là xử lý toàn bộ quy trình đăng nhập bằng Firebase Android SDK.

Để xử lý quy trình đăng nhập với SDK Android Firebase, hãy làm theo các bước sau:

  1. Xây dựng một thể hiện của một OAuthProvider sử dụng Builder của nó với nhà cung cấp ID apple.com :

    Java

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

    Kotlin + KTX

    val provider = OAuthProvider.newBuilder("apple.com")
    
  2. Tùy chọn: Xác định thêm OAuth 2.0 phạm vi vượt ra ngoài mặc định mà bạn muốn yêu cầu từ nhà cung cấp chứng thực.

    Java

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

    Kotlin + KTX

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

    Theo mặc định, khi một tài khoản cho mỗi địa chỉ email được kích hoạt, căn cứ hỏa lực yêu cầu email và tên phạm vi. Nếu bạn thay đổi cài đặt này để Nhiều tài khoản cho mỗi địa chỉ email, căn cứ hỏa lực không yêu cầu bất kỳ phạm vi từ Apple, trừ khi bạn xác định chúng.

  3. Tùy chọn: Nếu bạn muốn hiển thị của Apple màn hình đăng nhập bằng một ngôn ngữ khác ngoài tiếng Anh, thiết lập locale tham số. Xem Đăng nhập với tài liệu của Apple cho miền địa phương được hỗ trợ.

    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. Xác thực với Firebase bằng đối tượng nhà cung cấp OAuth. Lưu ý rằng không giống như khác FirebaseAuth hoạt động, điều này sẽ nắm quyền kiểm soát của giao diện người dùng của bạn bằng cách mở một tab tùy chỉnh Chrome. Do đó, không tham khảo hoạt động của bạn trong OnSuccessListenerOnFailureListener mà bạn đính kèm vì chúng sẽ ngay lập tức tách khi hoạt động bắt đầu từ giao diện người dùng.

    Trước tiên, bạn nên kiểm tra xem bạn đã nhận được phản hồi chưa. Đăng nhập bằng phương pháp này đặt Hoạt động của bạn ở chế độ nền, có nghĩa là hệ thống có thể xác nhận lại hoạt động đó trong quá trình đăng nhập. Để đảm bảo rằng bạn không bắt người dùng thử lại nếu điều này xảy ra, bạn nên kiểm tra xem đã có kết quả chưa.

    Để kiểm tra nếu có một kết quả chờ giải quyết, gọi 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")
    }
    

    Nếu không có kết quả chờ giải quyết, bắt đầu đăng nhập dòng chảy, bằng cách gọi 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)
            }
    

    Không giống như các nhà cung cấp khác được Firebase Auth hỗ trợ, Apple không cung cấp URL ảnh.

    Ngoài ra, khi người dùng chọn không chia sẻ email của họ với các ứng dụng, các quy định của Apple một địa chỉ email duy nhất cho người dùng đó (có dạng xyz@privaterelay.appleid.com ), mà nó chia sẻ với ứng dụng của bạn. Nếu bạn đã định cấu hình dịch vụ chuyển tiếp email riêng tư, Apple sẽ chuyển tiếp các email được gửi đến địa chỉ ẩn danh đến địa chỉ email thực của người dùng.

    Táo thông tin chỉ chia sẻ người dùng như tên hiển thị với các ứng dụng lần đầu tiên một người dùng đăng nhập. Thông thường, căn cứ hỏa lực các cửa hàng tên hiển thị lần đầu tiên một người dùng đăng nhập với Apple, mà bạn có thể nhận được với getCurrentUser().getDisplayName() . Tuy nhiên, nếu trước đây bạn đã sử dụng Apple để đăng nhập người dùng vào ứng dụng mà không sử dụng Firebase, thì Apple sẽ không cung cấp cho Firebase tên hiển thị của người dùng.

Xác thực lại và liên kết tài khoản

Các mô hình tương tự có thể được sử dụng với startActivityForReauthenticateWithProvider() mà bạn có thể sử dụng để lấy một chứng chỉ mới cho các hoạt động nhạy cảm đòi hỏi phải đăng nhập gần đây:

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

Và, bạn có thể sử dụng linkWithCredential() để liên kết các nhà cung cấp danh tính khác nhau vào các tài khoản hiện có.

Lưu ý rằng Apple yêu cầu bạn phải có sự đồng ý rõ ràng từ người dùng trước khi bạn liên kết tài khoản Apple của họ với dữ liệu khác.

Ví dụ: để liên kết tài khoản Facebook với tài khoản Firebase hiện tại, hãy sử dụng mã thông báo truy cập bạn nhận được khi đăng nhập người dùng vào 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.
        }
      });

Nâng cao: Xử lý quy trình đăng nhập theo cách thủ công

Bạn cũng có thể xác thực với căn cứ hỏa lực sử dụng một tài khoản của Apple bằng cách xử lý luồng đăng nhập bằng một trong hai cách sử dụng của Apple Đăng trong JS SDK, tay xây dựng dòng chảy OAuth hoặc bằng cách sử dụng một thư viện OAuth như AppAuth .

  1. Đối với mọi yêu cầu đăng nhập, hãy tạo một chuỗi ngẫu nhiên — "nonce" —mà bạn sẽ sử dụng để đảm bảo mã thông báo ID mà bạn nhận được đã được cấp cụ thể để đáp ứng yêu cầu xác thực của ứng dụng của bạn. Bước này rất quan trọng để ngăn chặn các cuộc tấn công phát lại.

    Bạn có thể tạo ra một nonce mã hóa bảo mật trên Android với SecureRandom , như trong ví dụ sau:

    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()
    }
    

    Sau đó, lấy hàm băm SHA246 của nonce dưới dạng chuỗi hex:

    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()
    }
    

    Bạn sẽ gửi hàm băm SHA256 của nonce cùng với yêu cầu đăng nhập của mình, mà Apple sẽ chuyển không thay đổi trong phản hồi. Firebase xác thực phản hồi bằng cách băm nonce ban đầu và so sánh nó với giá trị mà Apple đã chuyển.

  2. Bắt đầu quy trình đăng nhập của Apple bằng thư viện OAuth của bạn hoặc phương pháp khác. Đảm bảo bao gồm nonce được băm làm tham số trong yêu cầu của bạn.

  3. Sau khi nhận được phản ứng của Apple, có được ID token từ phản ứng và sử dụng nó và nonce unhashed để tạo ra một 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. Xác thực với Firebase bằng thông tin đăng nhập 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.
                // ...
              }
          }
    

Nếu cuộc gọi đến signInWithCredential thành công, bạn có thể sử dụng getCurrentUser phương pháp để có được dữ liệu tài khoản của người dùng.

Bước tiếp theo

Sau khi người dùng đăng nhập lần đầu tiên, tài khoản người dùng mới sẽ được tạo và liên kết với thông tin đăng nhập — nghĩa là tên người dùng và mật khẩu, số điện thoại hoặc thông tin nhà cung cấp xác thực — người dùng đã đăng nhập bằng. Tài khoản mới này được lưu trữ như một phần của dự án Firebase của bạn và có thể được sử dụng để xác định người dùng trên mọi ứng dụng trong dự án của bạn, bất kể người dùng đăng nhập bằng cách nào.

  • Trong các ứng dụng của bạn, bạn có thể nhận được thông tin hồ sơ cơ bản của người dùng từ các FirebaseUser đối tượng. Xem Quản lý người dùng .

  • Trong Cơ sở dữ liệu căn cứ hỏa lực Realtime của bạn và lưu trữ đám mây Security Rules , bạn có thể nhận được đã đăng nhập của người sử dụng ID người dùng duy nhất từ auth biến, và sử dụng nó để kiểm soát dữ liệu người dùng có thể truy cập.

Bạn có thể cho phép người dùng đăng nhập vào ứng dụng của bạn sử dụng nhiều nhà cung cấp chứng thực bởi liên kết auth thông tin cung cấp cho một tài khoản người dùng hiện có.

Đăng xuất khỏi một người sử dụng, hãy gọi signOut :

Java

FirebaseAuth.getInstance().signOut();

Kotlin + KTX

Firebase.auth.signOut()