Xác thực bằng Apple bằng JavaScript

Bạn có thể cho phép người dùng xác thực bằng Firebase bằng ID Apple của họ bằng cách sử dụng SDK Firebase để thực hiện luồng đăng nhập OAuth 2.0 từ đầu đến cuối.

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 bằng 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 của Apple

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

Định cấu hình Đăng nhập bằng Apple

Trên trang web Nhà phát triển Apple , hãy thực hiện như sau:

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

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

    Bạn có thể lấy ID dự án Firebase của mình trên trang cài đặt bảng điều khiển Firebase .

    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 Đăng nhập bằng khóa riêng của Apple . Bạn sẽ cần khóa riêng và ID khóa mới trong phần tiếp theo.
  3. Nếu bạn sử dụng bất kỳ tính năng nào của Xác thực Firebase để gửi email cho người dùng, bao gồm đăng nhập liên kết email, xác minh địa chỉ email, thu hồi thay đổi tài khoản và các tính năng khác, hãy định cấu hình dịch vụ chuyển tiếp email riêng tư 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 được gửi bởi Xác thực Firebase đế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 Firebase vào dự án của bạn .
  2. Trong bảng điều khiển Firebase , hãy mở phần Xác thực . Trên tab Phương thức đăng nhập , kích hoạt nhà cung cấp Apple . Chỉ định ID dịch vụ bạn đã tạo ở phần trước. Ngoài ra, trong phần cấu hình luồng mã OAuth , hãy chỉ định ID nhóm Apple của bạn cũng như khóa riêng và ID khóa bạn đã tạo ở 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 bằng Apple cung cấp cho người dùng tùy chọn ẩn danh dữ liệu của họ, bao gồm cả địa chỉ email, khi đăng nhập. Người dùng chọn tùy chọn này có địa chỉ email có tên miền privaterelay.appleid.com . Khi 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 liên quan đến các ID Apple ẩn danh này.

Điều này bao gồm việc có đượ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 xác thực 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 dành cho nhà phát triển của Apple trong phần Thành viên trong 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ý luồng đăng nhập bằng SDK Firebase

Nếu bạn đang xây dựng một ứng dụng web, 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ộ luồng đăng nhập bằng SDK JavaScript của Firebase.

Để xử lý luồng đăng nhập bằng SDK JavaScript Firebase, hãy làm theo các bước sau:

  1. Tạo một phiên bản của OAuthProvider bằng ID nhà cung cấp tương ứng apple.com .

    Web modular API

    import { OAuthProvider } from "firebase/auth";
    
    const provider = new OAuthProvider('apple.com');

    Web namespaced API

    var provider = new firebase.auth.OAuthProvider('apple.com');
  2. Tùy chọn: Chỉ định phạm vi OAuth 2.0 bổ sung ngoài phạm vi mặc định mà bạn muốn yêu cầu từ nhà cung cấp xác thực.

    Web modular API

    provider.addScope('email');
    provider.addScope('name');

    Web namespaced API

    provider.addScope('email');
    provider.addScope('name');

    Theo mặc định, khi bật Một tài khoản cho mỗi địa chỉ email , Firebase sẽ yêu cầu phạm vi tên và email. Nếu bạn thay đổi cài đặt này thành Nhiều tài khoản trên mỗi địa chỉ email thì Firebase sẽ không yêu cầu bất kỳ phạm vi nào từ Apple trừ khi bạn chỉ định chúng.

  3. Tùy chọn: Nếu bạn muốn hiển thị màn hình đăng nhập của Apple bằng ngôn ngữ khác tiếng Anh, hãy đặt tham số locale . Xem tài liệu Đăng nhập bằng Apple để biết các ngôn ngữ được hỗ trợ.

    Web modular API

    provider.setCustomParameters({
      // Localize the Apple authentication screen in French.
      locale: 'fr'
    });

    Web namespaced API

    provider.setCustomParameters({
      // Localize the Apple authentication screen in French.
      locale: 'fr'
    });
  4. Xác thực với Firebase bằng đối tượng nhà cung cấp OAuth. Bạn có thể nhắc người dùng đăng nhập bằng Tài khoản Apple của họ bằng cách mở cửa sổ bật lên hoặc bằng cách chuyển hướng đến trang đăng nhập. Phương pháp chuyển hướng được ưa thích trên thiết bị di động.

    • Để đăng nhập bằng cửa sổ bật lên, hãy gọi signInWithPopup() :

      Web modular API

      import { getAuth, signInWithPopup, OAuthProvider } from "firebase/auth";
      
      const auth = getAuth();
      signInWithPopup(auth, provider)
        .then((result) => {
          // The signed-in user info.
          const user = result.user;
      
          // Apple credential
          const credential = OAuthProvider.credentialFromResult(result);
          const accessToken = credential.accessToken;
          const idToken = credential.idToken;
      
          // IdP data available using getAdditionalUserInfo(result)
          // ...
        })
        .catch((error) => {
          // Handle Errors here.
          const errorCode = error.code;
          const errorMessage = error.message;
          // The email of the user's account used.
          const email = error.customData.email;
          // The credential that was used.
          const credential = OAuthProvider.credentialFromError(error);
      
          // ...
        });

      Web namespaced API

      firebase
        .auth()
        .signInWithPopup(provider)
        .then((result) => {
          /** @type {firebase.auth.OAuthCredential} */
          var credential = result.credential;
      
          // The signed-in user info.
          var user = result.user;
      
          // You can also get the Apple OAuth Access and ID Tokens.
          var accessToken = credential.accessToken;
          var idToken = credential.idToken;
      
          // IdP data available using getAdditionalUserInfo(result)
        // ...
        })
        .catch((error) => {
          // Handle Errors here.
          var errorCode = error.code;
          var errorMessage = error.message;
          // The email of the user's account used.
          var email = error.email;
          // The firebase.auth.AuthCredential type that was used.
          var credential = error.credential;
      
          // ...
        });
    • Để đăng nhập bằng cách chuyển hướng đến trang đăng nhập, hãy gọi signInWithRedirect() :

    Thực hiện theo các phương pháp hay nhất khi sử dụng signInWithRedirect , linkWithRedirect hoặc reauthenticateWithRedirect .

    Web modular API

    import { getAuth, signInWithRedirect } from "firebase/auth";
    
    const auth = getAuth();
    signInWithRedirect(auth, provider);

    Web namespaced API

    firebase.auth().signInWithRedirect(provider);

    Sau khi người dùng hoàn tất đăng nhập và quay lại trang, bạn có thể nhận kết quả đăng nhập bằng cách gọi getRedirectResult() :

    Web modular API

    import { getAuth, getRedirectResult, OAuthProvider } from "firebase/auth";
    
    // Result from Redirect auth flow.
    const auth = getAuth();
    getRedirectResult(auth)
      .then((result) => {
        const credential = OAuthProvider.credentialFromResult(result);
        if (credential) {
          // You can also get the Apple OAuth Access and ID Tokens.
          const accessToken = credential.accessToken;
          const idToken = credential.idToken;
        }
        // The signed-in user info.
        const user = result.user;
      })
      .catch((error) => {
        // Handle Errors here.
        const errorCode = error.code;
        const errorMessage = error.message;
        // The email of the user's account used.
        const email = error.customData.email;
        // The credential that was used.
        const credential = OAuthProvider.credentialFromError(error);
    
        // ...
      });

    Web namespaced API

    // Result from Redirect auth flow.
    firebase
      .auth()
      .getRedirectResult()
      .then((result) => {
        if (result.credential) {
          /** @type {firebase.auth.OAuthCredential} */
          var credential = result.credential;
    
          // You can get the Apple OAuth Access and ID Tokens.
          var accessToken = credential.accessToken;
          var idToken = credential.idToken;
    
          // IdP data available in result.additionalUserInfo.profile.
          // ...
        }
        // The signed-in user info.
        var user = result.user;
      })
      .catch((error) => {
        // Handle Errors here.
        var errorCode = error.code;
        var errorMessage = error.message;
        // The email of the user's account used.
        var email = error.email;
        // The firebase.auth.AuthCredential type that was used.
        var credential = error.credential;
    
        // ...
      });

    Đây cũng là nơi bạn có thể bắt và xử lý lỗi. Để biết danh sách mã lỗi, hãy xem tài liệu tham khảo API .

    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 ứng dụng, Apple sẽ cung cấp một địa chỉ email duy nhất cho người dùng đó (có dạng xyz@privaterelay.appleid.com ) mà họ 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 tới địa chỉ email thực của người dùng.

    Apple chỉ chia sẻ thông tin người dùng như tên hiển thị với các ứng dụng trong lần đầu tiên người dùng đăng nhập. Thông thường, Firebase lưu trữ tên hiển thị trong lần đầu tiên người dùng đăng nhập bằng Apple. Bạn có thể lấy tên này bằng firebase.auth().currentUser.displayName . 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

Bạn có thể sử dụng mẫu tương tự với reauthenticateWithPopup()reauthenticateWithRedirect() mà bạn có thể sử dụng để truy xuất thông tin xác thực mới cho các hoạt động nhạy cảm yêu cầu đăng nhập gần đây:

Web modular API

import { getAuth, reauthenticateWithPopup, OAuthProvider } from "firebase/auth";

// Result from Redirect auth flow.
const auth = getAuth();
const provider = new OAuthProvider('apple.com');

reauthenticateWithPopup(auth.currentUser, provider)
  .then((result) => {
    // User is re-authenticated with fresh tokens minted and can perform
    // sensitive operations like account deletion, or updating their email
    // address or password.

    // The signed-in user info.
    const user = result.user;

    // You can also get the Apple OAuth Access and ID Tokens.
    const credential = OAuthProvider.credentialFromResult(result);
    const accessToken = credential.accessToken;
    const idToken = credential.idToken;

    // ...
  })
  .catch((error) => {
    // Handle Errors here.
    const errorCode = error.code;
    const errorMessage = error.message;
    // The email of the user's account used.
    const email = error.customData.email;
    // The credential that was used.
    const credential = OAuthProvider.credentialFromError(error);

    // ...
  });

Web namespaced API

const provider = new firebase.auth.OAuthProvider('apple.com');

firebase
  .auth()
  .currentUser
  .reauthenticateWithPopup(provider)
  .then((result) => {
    // User is re-authenticated with fresh tokens minted and can perform
    // sensitive operations like account deletion, or updating their email
    // address or password.
    /** @type {firebase.auth.OAuthCredential} */
    var credential = result.credential;

    // The signed-in user info.
    var user = result.user;
     // You can also get the Apple OAuth Access and ID Tokens.
    var accessToken = credential.accessToken;
    var idToken = credential.idToken;

    // IdP data available in result.additionalUserInfo.profile.
      // ...
  })
  .catch((error) => {
    // Handle Errors here.
    var errorCode = error.code;
    var errorMessage = error.message;
    // The email of the user's account used.
    var email = error.email;
    // The firebase.auth.AuthCredential type that was used.
    var credential = error.credential;

    // ...
  });

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

Lưu ý rằng Apple yêu cầu bạn phải nhận được sự đồng ý rõ ràng từ người dùng trước khi 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:

Web modular API

import { getAuth, linkWithPopup, FacebookAuthProvider } from "firebase/auth";

const auth = getAuth();
const provider = new FacebookAuthProvider();
provider.addScope('user_birthday');

// Assuming the current user is an Apple user linking a Facebook provider.
linkWithPopup(auth.currentUser, provider)
    .then((result) => {
      // Facebook credential is linked to the current Apple user.
      // ...

      // The user can now sign in to the same account
      // with either Apple or Facebook.
    })
    .catch((error) => {
      // Handle error.
    });

Web namespaced API

const provider = new firebase.auth.FacebookAuthProvider();
provider.addScope('user_birthday');

// Assuming the current user is an Apple user linking a Facebook provider.
firebase.auth().currentUser.linkWithPopup(provider)
    .then((result) => {
      // Facebook credential is linked to the current Apple user.
      // Facebook additional data available in result.additionalUserInfo.profile,

      // Additional Facebook OAuth access token can also be retrieved.
      // result.credential.accessToken

      // The user can now sign in to the same account
      // with either Apple or Facebook.
    })
    .catch((error) => {
      // Handle error.
    });

Xác thực bằng Firebase trong tiện ích mở rộng của Chrome

Nếu bạn đang xây dựng một ứng dụng tiện ích mở rộng của Chrome, hãy xem hướng dẫn Tài liệu ngoài màn hình .

Lưu ý rằng bạn vẫn phải xác minh miền tùy chỉnh với Apple tương tự như miền firebaseapp.com mặc định:

http://auth.custom.example.com/.well-known/apple-developer-domain-association.txt

Thu hồi mã thông báo

Apple yêu cầu các ứng dụng hỗ trợ tạo tài khoản phải cho phép người dùng bắt đầu xóa tài khoản của họ trong ứng dụng, như được mô tả trong Nguyên tắc đánh giá của App Store

Để đáp ứng yêu cầu này, hãy thực hiện các bước sau:

  1. Đảm bảo bạn đã điền vào phần cấu hình luồng mã OAuthID dịch vụ của cấu hình nhà cung cấp Đăng nhập bằng Apple, như được nêu trong phần Định cấu hình Đăng nhập bằng Apple .

  2. Vì Firebase không lưu trữ mã thông báo của người dùng khi người dùng được tạo bằng Đăng nhập bằng Apple nên bạn phải yêu cầu người dùng đăng nhập lại trước khi thu hồi mã thông báo của họ và xóa tài khoản.

    Sau đó, lấy mã thông báo truy cập Apple OAuth từ OAuthCredential và sử dụng nó để gọi revokeAccessToken(auth, token) nhằm thu hồi mã thông báo truy cập Apple OAuth.

    const provider = new OAuthProvider('apple.com');
    provider.addScope('email');
    provider.addScope('name');
    
    const auth = getAuth();
    signInWithPopup(auth, provider).then(result => {
      // Get the Apple OAuth access token.
      const credential = OAuthProvider.credentialFromResult(result);
      const accessToken = credential.accessToken;
    
      // Revoke the Apple OAuth access token.
      revokeAccessToken(auth, accessToken)
        .then(() => {
          // Token revoked.
    
          // Delete the user account.
          // ...
        })
        .catch(error => {
          // An error happened.
          // ...
        });
    });
    
  3. Cuối cùng, xóa tài khoản người dùng (và tất cả dữ liệu liên quan).

Nâng cao: Xác thực bằng Firebase trong Node.js

Để xác thực bằng Firebase trong ứng dụng Node.js:

  1. Đăng nhập người dùng bằng Tài khoản Apple của họ và nhận mã thông báo Apple ID của người dùng. Bạn có thể thực hiện điều này bằng nhiều cách. Ví dụ: nếu ứng dụng Node.js của bạn có giao diện người dùng trình duyệt:

    1. Trên phần phụ trợ của bạn, tạo một chuỗi ngẫu nhiên ("nonce") và tính toán hàm băm SHA256 của nó. Nonce là giá trị sử dụng một lần mà bạn sử dụng để xác thực một chuyến đi khứ hồi giữa chương trình phụ trợ của bạn và máy chủ xác thực của Apple.

      Web modular API

      const crypto = require("crypto");
      const string_decoder = require("string_decoder");
      
      // Generate a new random string for each sign-in
      const generateNonce = (length) => {
        const decoder = new string_decoder.StringDecoder("ascii");
        const buf = Buffer.alloc(length);
        let nonce = "";
        while (nonce.length < length) {
          crypto.randomFillSync(buf);
          nonce = decoder.write(buf);
        }
        return nonce.slice(0, length);
      };
      
      const unhashedNonce = generateNonce(10);
      
      // SHA256-hashed nonce in hex
      const hashedNonceHex = crypto.createHash('sha256')
        .update(unhashedNonce).digest().toString('hex');

      Web namespaced API

      const crypto = require("crypto");
      const string_decoder = require("string_decoder");
      
      // Generate a new random string for each sign-in
      const generateNonce = function(length) {
        const decoder = new string_decoder.StringDecoder("ascii");
        const buf = Buffer.alloc(length);
        var nonce = "";
        while (nonce.length < length) {
          crypto.randomFillSync(buf);
          nonce = decoder.write(buf);
        }
        return nonce.slice(0, length);
      };
      
      const unhashedNonce = generateNonce(10);
      
      // SHA256-hashed nonce in hex
      const hashedNonceHex = crypto.createHash('sha256')
        .update(unhashedNonce).digest().toString('hex');
    2. Trên trang đăng nhập của bạn, hãy chỉ định số không được băm trong cấu hình Đăng nhập bằng Apple của bạn:

      <script src="https://appleid.cdn-apple.com/appleauth/static/jsapi/appleid/1/en_US/appleid.auth.js"></script>
      <div id="appleid-signin" data-color="black" data-border="true" data-type="sign in"></div>
      <script>
          AppleID.auth.init({
              clientId: YOUR_APPLE_CLIENT_ID,
              scope: 'name email',
              redirectURI: URL_TO_YOUR_REDIRECT_HANDLER,  // See the next step.
              state: '[STATE]',  // Optional value that Apple will send back to you
                                 // so you can return users to the same context after
                                 // they sign in.
              nonce: HASHED_NONCE  // The hashed nonce you generated in the previous step.
          });
      </script>
      
    3. Nhận mã thông báo Apple ID từ phía máy chủ phản hồi xác thực đã đăng:

      app.post('/redirect', (req, res) => {
        const savedState = req.cookies.__session;
        const code = req.body.code;
        const state = req.body.state;
        const appleIdToken = req.body.id_token;
        if (savedState !== state || !code) {
          res.status(403).send('403: Permission denied');
        } else {
          // Sign in with Firebase using appleIdToken. (See next step).
        }
      });
      

    Đồng thời xem Định cấu hình trang web của bạn để đăng nhập bằng Apple .

  2. Sau khi bạn nhận được mã thông báo Apple ID của người dùng, hãy sử dụng nó để xây dựng đối tượng Thông tin xác thực và sau đó đăng nhập vào người dùng bằng thông tin xác thực:

    Web modular API

    import { getAuth, signInWithCredential, OAuthProvider } from "firebase/auth";
    
    const auth = getAuth();
    
    // Build Firebase credential with the Apple ID token.
    const provider = new OAuthProvider('apple.com');
    const authCredential = provider.credential({
      idToken: appleIdToken,
      rawNonce: unhashedNonce,
    });
    
    // Sign in with credential form the Apple user.
    signInWithCredential(auth, authCredential)
      .then((result) => {
        // User signed in.
      })
      .catch((error) => {
        // An error occurred. If error.code == 'auth/missing-or-invalid-nonce',
        // make sure you're sending the SHA256-hashed nonce as a hex string
        // with your request to Apple.
        console.log(error);
      });

    Web namespaced API

    // Build Firebase credential with the Apple ID token.
    const provider = new firebase.auth.OAuthProvider('apple.com');
    const authCredential = provider.credential({
      idToken: appleIdToken,
      rawNonce: unhashedNonce,
    });
    
    // Sign in with credential form the Apple user.
    firebase.auth().signInWithCredential(authCredential)
      .then((result) => {
        // User signed in.
      })
      .catch((error) => {
        // An error occurred. If error.code == 'auth/missing-or-invalid-nonce',
        // make sure you're sending the SHA256-hashed nonce as a hex string
        // with your request to Apple.
        console.log(error);
      });

Bước tiếp theo

Sau khi người dùng đăng nhập lần đầu tiên, một tài khoản người dùng mới sẽ được tạo và liên kết với thông tin xác thực—tức 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 dịch vụ xác thực—mà người dùng đã đăng nhập. 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 ứng dụng của bạn, cách được khuyên dùng để biết trạng thái xác thực của người dùng là đặt trình quan sát trên đối tượng Auth . Sau đó, bạn có thể lấy thông tin hồ sơ cơ bản của người dùng từ đối tượng User . Xem Quản lý người dùng .

  • Trong Quy tắc bảo mật cơ sở dữ liệu thời gian thực và lưu trữ đám mây của Firebase, bạn có thể lấy ID người dùng duy nhất của người dùng đã đăng nhập từ biến auth và sử dụng nó để kiểm soát dữ liệu nào 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 mình bằng nhiều nhà cung cấp xác thực bằng cách liên kết thông tin xác thực của nhà cung cấp xác thực với tài khoản người dùng hiện có.

Để đăng xuất người dùng, hãy gọi signOut :

Web modular API

import { getAuth, signOut } from "firebase/auth";

const auth = getAuth();
signOut(auth).then(() => {
  // Sign-out successful.
}).catch((error) => {
  // An error happened.
});

Web namespaced API

firebase.auth().signOut().then(() => {
  // Sign-out successful.
}).catch((error) => {
  // An error happened.
});
,

Bạn có thể cho phép người dùng xác thực bằng Firebase bằng ID Apple của họ bằng cách sử dụng SDK Firebase để thực hiện luồng đăng nhập OAuth 2.0 từ đầu đến cuối.

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 bằng 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 của Apple

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

Định cấu hình Đăng nhập bằng Apple

Trên trang web Nhà phát triển Apple , hãy thực hiện như sau:

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

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

    Bạn có thể lấy ID dự án Firebase của mình trên trang cài đặt bảng điều khiển Firebase .

    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 Đăng nhập bằng khóa riêng của Apple . Bạn sẽ cần khóa riêng và ID khóa mới trong phần tiếp theo.
  3. Nếu bạn sử dụng bất kỳ tính năng nào của Xác thực Firebase để gửi email cho người dùng, bao gồm đăng nhập liên kết email, xác minh địa chỉ email, thu hồi thay đổi tài khoản và các tính năng khác, hãy định cấu hình dịch vụ chuyển tiếp email riêng tư 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 được gửi bởi Xác thực Firebase đế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 Firebase vào dự án của bạn .
  2. Trong bảng điều khiển Firebase , hãy mở phần Xác thực . Trên tab Phương thức đăng nhập , kích hoạt nhà cung cấp Apple . Chỉ định ID dịch vụ bạn đã tạo ở phần trước. Ngoài ra, trong phần cấu hình luồng mã OAuth , hãy chỉ định ID nhóm Apple của bạn cũng như khóa riêng và ID khóa bạn đã tạo ở 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 bằng Apple cung cấp cho người dùng tùy chọn ẩn danh dữ liệu của họ, bao gồm cả địa chỉ email, khi đăng nhập. Người dùng chọn tùy chọn này có địa chỉ email có tên miền privaterelay.appleid.com . Khi 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 liên quan đến các ID Apple ẩn danh này.

Điều này bao gồm việc có đượ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 xác thực 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 dành cho nhà phát triển của Apple trong phần Thành viên trong 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ý luồng đăng nhập bằng SDK Firebase

Nếu bạn đang xây dựng một ứng dụng web, 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ộ luồng đăng nhập bằng SDK JavaScript của Firebase.

Để xử lý luồng đăng nhập bằng SDK JavaScript Firebase, hãy làm theo các bước sau:

  1. Tạo một phiên bản của OAuthProvider bằng ID nhà cung cấp tương ứng apple.com .

    Web modular API

    import { OAuthProvider } from "firebase/auth";
    
    const provider = new OAuthProvider('apple.com');

    Web namespaced API

    var provider = new firebase.auth.OAuthProvider('apple.com');
  2. Tùy chọn: Chỉ định phạm vi OAuth 2.0 bổ sung ngoài phạm vi mặc định mà bạn muốn yêu cầu từ nhà cung cấp xác thực.

    Web modular API

    provider.addScope('email');
    provider.addScope('name');

    Web namespaced API

    provider.addScope('email');
    provider.addScope('name');

    Theo mặc định, khi bật Một tài khoản cho mỗi địa chỉ email , Firebase sẽ yêu cầu phạm vi tên và email. Nếu bạn thay đổi cài đặt này thành Nhiều tài khoản trên mỗi địa chỉ email thì Firebase sẽ không yêu cầu bất kỳ phạm vi nào từ Apple trừ khi bạn chỉ định chúng.

  3. Tùy chọn: Nếu bạn muốn hiển thị màn hình đăng nhập của Apple bằng ngôn ngữ khác tiếng Anh, hãy đặt tham số locale . Xem tài liệu Đăng nhập bằng Apple để biết các ngôn ngữ được hỗ trợ.

    Web modular API

    provider.setCustomParameters({
      // Localize the Apple authentication screen in French.
      locale: 'fr'
    });

    Web namespaced API

    provider.setCustomParameters({
      // Localize the Apple authentication screen in French.
      locale: 'fr'
    });
  4. Xác thực với Firebase bằng đối tượng nhà cung cấp OAuth. Bạn có thể nhắc người dùng đăng nhập bằng Tài khoản Apple của họ bằng cách mở cửa sổ bật lên hoặc bằng cách chuyển hướng đến trang đăng nhập. Phương pháp chuyển hướng được ưa thích trên thiết bị di động.

    • Để đăng nhập bằng cửa sổ bật lên, hãy gọi signInWithPopup() :

      Web modular API

      import { getAuth, signInWithPopup, OAuthProvider } from "firebase/auth";
      
      const auth = getAuth();
      signInWithPopup(auth, provider)
        .then((result) => {
          // The signed-in user info.
          const user = result.user;
      
          // Apple credential
          const credential = OAuthProvider.credentialFromResult(result);
          const accessToken = credential.accessToken;
          const idToken = credential.idToken;
      
          // IdP data available using getAdditionalUserInfo(result)
          // ...
        })
        .catch((error) => {
          // Handle Errors here.
          const errorCode = error.code;
          const errorMessage = error.message;
          // The email of the user's account used.
          const email = error.customData.email;
          // The credential that was used.
          const credential = OAuthProvider.credentialFromError(error);
      
          // ...
        });

      Web namespaced API

      firebase
        .auth()
        .signInWithPopup(provider)
        .then((result) => {
          /** @type {firebase.auth.OAuthCredential} */
          var credential = result.credential;
      
          // The signed-in user info.
          var user = result.user;
      
          // You can also get the Apple OAuth Access and ID Tokens.
          var accessToken = credential.accessToken;
          var idToken = credential.idToken;
      
          // IdP data available using getAdditionalUserInfo(result)
        // ...
        })
        .catch((error) => {
          // Handle Errors here.
          var errorCode = error.code;
          var errorMessage = error.message;
          // The email of the user's account used.
          var email = error.email;
          // The firebase.auth.AuthCredential type that was used.
          var credential = error.credential;
      
          // ...
        });
    • Để đăng nhập bằng cách chuyển hướng đến trang đăng nhập, hãy gọi signInWithRedirect() :

    Thực hiện theo các phương pháp hay nhất khi sử dụng signInWithRedirect , linkWithRedirect hoặc reauthenticateWithRedirect .

    Web modular API

    import { getAuth, signInWithRedirect } from "firebase/auth";
    
    const auth = getAuth();
    signInWithRedirect(auth, provider);

    Web namespaced API

    firebase.auth().signInWithRedirect(provider);

    Sau khi người dùng hoàn tất đăng nhập và quay lại trang, bạn có thể nhận kết quả đăng nhập bằng cách gọi getRedirectResult() :

    Web modular API

    import { getAuth, getRedirectResult, OAuthProvider } from "firebase/auth";
    
    // Result from Redirect auth flow.
    const auth = getAuth();
    getRedirectResult(auth)
      .then((result) => {
        const credential = OAuthProvider.credentialFromResult(result);
        if (credential) {
          // You can also get the Apple OAuth Access and ID Tokens.
          const accessToken = credential.accessToken;
          const idToken = credential.idToken;
        }
        // The signed-in user info.
        const user = result.user;
      })
      .catch((error) => {
        // Handle Errors here.
        const errorCode = error.code;
        const errorMessage = error.message;
        // The email of the user's account used.
        const email = error.customData.email;
        // The credential that was used.
        const credential = OAuthProvider.credentialFromError(error);
    
        // ...
      });

    Web namespaced API

    // Result from Redirect auth flow.
    firebase
      .auth()
      .getRedirectResult()
      .then((result) => {
        if (result.credential) {
          /** @type {firebase.auth.OAuthCredential} */
          var credential = result.credential;
    
          // You can get the Apple OAuth Access and ID Tokens.
          var accessToken = credential.accessToken;
          var idToken = credential.idToken;
    
          // IdP data available in result.additionalUserInfo.profile.
          // ...
        }
        // The signed-in user info.
        var user = result.user;
      })
      .catch((error) => {
        // Handle Errors here.
        var errorCode = error.code;
        var errorMessage = error.message;
        // The email of the user's account used.
        var email = error.email;
        // The firebase.auth.AuthCredential type that was used.
        var credential = error.credential;
    
        // ...
      });

    Đây cũng là nơi bạn có thể bắt và xử lý lỗi. Để biết danh sách mã lỗi, hãy xem tài liệu tham khảo API .

    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 ứng dụng, Apple sẽ cung cấp một địa chỉ email duy nhất cho người dùng đó (có dạng xyz@privaterelay.appleid.com ) mà họ 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 tới địa chỉ email thực của người dùng.

    Apple chỉ chia sẻ thông tin người dùng như tên hiển thị với các ứng dụng trong lần đầu tiên người dùng đăng nhập. Thông thường, Firebase lưu trữ tên hiển thị trong lần đầu tiên người dùng đăng nhập bằng Apple. Bạn có thể lấy tên này bằng firebase.auth().currentUser.displayName . 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

Bạn có thể sử dụng mẫu tương tự với reauthenticateWithPopup()reauthenticateWithRedirect() mà bạn có thể sử dụng để truy xuất thông tin xác thực mới cho các hoạt động nhạy cảm yêu cầu đăng nhập gần đây:

Web modular API

import { getAuth, reauthenticateWithPopup, OAuthProvider } from "firebase/auth";

// Result from Redirect auth flow.
const auth = getAuth();
const provider = new OAuthProvider('apple.com');

reauthenticateWithPopup(auth.currentUser, provider)
  .then((result) => {
    // User is re-authenticated with fresh tokens minted and can perform
    // sensitive operations like account deletion, or updating their email
    // address or password.

    // The signed-in user info.
    const user = result.user;

    // You can also get the Apple OAuth Access and ID Tokens.
    const credential = OAuthProvider.credentialFromResult(result);
    const accessToken = credential.accessToken;
    const idToken = credential.idToken;

    // ...
  })
  .catch((error) => {
    // Handle Errors here.
    const errorCode = error.code;
    const errorMessage = error.message;
    // The email of the user's account used.
    const email = error.customData.email;
    // The credential that was used.
    const credential = OAuthProvider.credentialFromError(error);

    // ...
  });

Web namespaced API

const provider = new firebase.auth.OAuthProvider('apple.com');

firebase
  .auth()
  .currentUser
  .reauthenticateWithPopup(provider)
  .then((result) => {
    // User is re-authenticated with fresh tokens minted and can perform
    // sensitive operations like account deletion, or updating their email
    // address or password.
    /** @type {firebase.auth.OAuthCredential} */
    var credential = result.credential;

    // The signed-in user info.
    var user = result.user;
     // You can also get the Apple OAuth Access and ID Tokens.
    var accessToken = credential.accessToken;
    var idToken = credential.idToken;

    // IdP data available in result.additionalUserInfo.profile.
      // ...
  })
  .catch((error) => {
    // Handle Errors here.
    var errorCode = error.code;
    var errorMessage = error.message;
    // The email of the user's account used.
    var email = error.email;
    // The firebase.auth.AuthCredential type that was used.
    var credential = error.credential;

    // ...
  });

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

Lưu ý rằng Apple yêu cầu bạn phải nhận được sự đồng ý rõ ràng từ người dùng trước khi 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:

Web modular API

import { getAuth, linkWithPopup, FacebookAuthProvider } from "firebase/auth";

const auth = getAuth();
const provider = new FacebookAuthProvider();
provider.addScope('user_birthday');

// Assuming the current user is an Apple user linking a Facebook provider.
linkWithPopup(auth.currentUser, provider)
    .then((result) => {
      // Facebook credential is linked to the current Apple user.
      // ...

      // The user can now sign in to the same account
      // with either Apple or Facebook.
    })
    .catch((error) => {
      // Handle error.
    });

Web namespaced API

const provider = new firebase.auth.FacebookAuthProvider();
provider.addScope('user_birthday');

// Assuming the current user is an Apple user linking a Facebook provider.
firebase.auth().currentUser.linkWithPopup(provider)
    .then((result) => {
      // Facebook credential is linked to the current Apple user.
      // Facebook additional data available in result.additionalUserInfo.profile,

      // Additional Facebook OAuth access token can also be retrieved.
      // result.credential.accessToken

      // The user can now sign in to the same account
      // with either Apple or Facebook.
    })
    .catch((error) => {
      // Handle error.
    });

Xác thực bằng Firebase trong tiện ích mở rộng của Chrome

Nếu bạn đang xây dựng một ứng dụng tiện ích mở rộng của Chrome, hãy xem hướng dẫn Tài liệu ngoài màn hình .

Lưu ý rằng bạn vẫn phải xác minh miền tùy chỉnh với Apple tương tự như miền firebaseapp.com mặc định:

http://auth.custom.example.com/.well-known/apple-developer-domain-association.txt

Thu hồi mã thông báo

Apple yêu cầu các ứng dụng hỗ trợ tạo tài khoản phải cho phép người dùng bắt đầu xóa tài khoản của họ trong ứng dụng, như được mô tả trong Nguyên tắc đánh giá của App Store

Để đáp ứng yêu cầu này, hãy thực hiện các bước sau:

  1. Đảm bảo bạn đã điền vào phần cấu hình luồng mã OAuthID dịch vụ của cấu hình nhà cung cấp Đăng nhập bằng Apple, như được nêu trong phần Định cấu hình Đăng nhập bằng Apple .

  2. Vì Firebase không lưu trữ mã thông báo của người dùng khi người dùng được tạo bằng Đăng nhập bằng Apple nên bạn phải yêu cầu người dùng đăng nhập lại trước khi thu hồi mã thông báo của họ và xóa tài khoản.

    Sau đó, lấy mã thông báo truy cập Apple OAuth từ OAuthCredential và sử dụng nó để gọi revokeAccessToken(auth, token) nhằm thu hồi mã thông báo truy cập Apple OAuth.

    const provider = new OAuthProvider('apple.com');
    provider.addScope('email');
    provider.addScope('name');
    
    const auth = getAuth();
    signInWithPopup(auth, provider).then(result => {
      // Get the Apple OAuth access token.
      const credential = OAuthProvider.credentialFromResult(result);
      const accessToken = credential.accessToken;
    
      // Revoke the Apple OAuth access token.
      revokeAccessToken(auth, accessToken)
        .then(() => {
          // Token revoked.
    
          // Delete the user account.
          // ...
        })
        .catch(error => {
          // An error happened.
          // ...
        });
    });
    
  3. Cuối cùng, xóa tài khoản người dùng (và tất cả dữ liệu liên quan).

Nâng cao: Xác thực bằng Firebase trong Node.js

Để xác thực bằng Firebase trong ứng dụng Node.js:

  1. Đăng nhập người dùng bằng Tài khoản Apple của họ và nhận mã thông báo Apple ID của người dùng. Bạn có thể thực hiện điều này bằng nhiều cách. Ví dụ: nếu ứng dụng Node.js của bạn có giao diện người dùng trình duyệt:

    1. Trên phần phụ trợ của bạn, tạo một chuỗi ngẫu nhiên ("nonce") và tính hàm băm SHA256 của nó. Nonce là giá trị sử dụng một lần mà bạn sử dụng để xác thực một chuyến đi khứ hồi giữa chương trình phụ trợ của bạn và máy chủ xác thực của Apple.

      Web modular API

      const crypto = require("crypto");
      const string_decoder = require("string_decoder");
      
      // Generate a new random string for each sign-in
      const generateNonce = (length) => {
        const decoder = new string_decoder.StringDecoder("ascii");
        const buf = Buffer.alloc(length);
        let nonce = "";
        while (nonce.length < length) {
          crypto.randomFillSync(buf);
          nonce = decoder.write(buf);
        }
        return nonce.slice(0, length);
      };
      
      const unhashedNonce = generateNonce(10);
      
      // SHA256-hashed nonce in hex
      const hashedNonceHex = crypto.createHash('sha256')
        .update(unhashedNonce).digest().toString('hex');

      Web namespaced API

      const crypto = require("crypto");
      const string_decoder = require("string_decoder");
      
      // Generate a new random string for each sign-in
      const generateNonce = function(length) {
        const decoder = new string_decoder.StringDecoder("ascii");
        const buf = Buffer.alloc(length);
        var nonce = "";
        while (nonce.length < length) {
          crypto.randomFillSync(buf);
          nonce = decoder.write(buf);
        }
        return nonce.slice(0, length);
      };
      
      const unhashedNonce = generateNonce(10);
      
      // SHA256-hashed nonce in hex
      const hashedNonceHex = crypto.createHash('sha256')
        .update(unhashedNonce).digest().toString('hex');
    2. Trên trang đăng nhập của bạn, hãy chỉ định số không được băm trong cấu hình Đăng nhập bằng Apple của bạn:

      <script src="https://appleid.cdn-apple.com/appleauth/static/jsapi/appleid/1/en_US/appleid.auth.js"></script>
      <div id="appleid-signin" data-color="black" data-border="true" data-type="sign in"></div>
      <script>
          AppleID.auth.init({
              clientId: YOUR_APPLE_CLIENT_ID,
              scope: 'name email',
              redirectURI: URL_TO_YOUR_REDIRECT_HANDLER,  // See the next step.
              state: '[STATE]',  // Optional value that Apple will send back to you
                                 // so you can return users to the same context after
                                 // they sign in.
              nonce: HASHED_NONCE  // The hashed nonce you generated in the previous step.
          });
      </script>
      
    3. Nhận mã thông báo Apple ID từ phía máy chủ phản hồi xác thực đã đăng:

      app.post('/redirect', (req, res) => {
        const savedState = req.cookies.__session;
        const code = req.body.code;
        const state = req.body.state;
        const appleIdToken = req.body.id_token;
        if (savedState !== state || !code) {
          res.status(403).send('403: Permission denied');
        } else {
          // Sign in with Firebase using appleIdToken. (See next step).
        }
      });
      

    Đồng thời xem Định cấu hình trang web của bạn để đăng nhập bằng Apple .

  2. Sau khi bạn nhận được mã thông báo Apple ID của người dùng, hãy sử dụng nó để tạo đối tượng Thông tin xác thực và sau đó đăng nhập vào người dùng bằng thông tin xác thực:

    Web modular API

    import { getAuth, signInWithCredential, OAuthProvider } from "firebase/auth";
    
    const auth = getAuth();
    
    // Build Firebase credential with the Apple ID token.
    const provider = new OAuthProvider('apple.com');
    const authCredential = provider.credential({
      idToken: appleIdToken,
      rawNonce: unhashedNonce,
    });
    
    // Sign in with credential form the Apple user.
    signInWithCredential(auth, authCredential)
      .then((result) => {
        // User signed in.
      })
      .catch((error) => {
        // An error occurred. If error.code == 'auth/missing-or-invalid-nonce',
        // make sure you're sending the SHA256-hashed nonce as a hex string
        // with your request to Apple.
        console.log(error);
      });

    Web namespaced API

    // Build Firebase credential with the Apple ID token.
    const provider = new firebase.auth.OAuthProvider('apple.com');
    const authCredential = provider.credential({
      idToken: appleIdToken,
      rawNonce: unhashedNonce,
    });
    
    // Sign in with credential form the Apple user.
    firebase.auth().signInWithCredential(authCredential)
      .then((result) => {
        // User signed in.
      })
      .catch((error) => {
        // An error occurred. If error.code == 'auth/missing-or-invalid-nonce',
        // make sure you're sending the SHA256-hashed nonce as a hex string
        // with your request to Apple.
        console.log(error);
      });

Bước tiếp theo

Sau khi người dùng đăng nhập lần đầu tiên, một tài khoản người dùng mới sẽ được tạo và liên kết với thông tin xác thực—tức 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 dịch vụ xác thực—mà người dùng đã đăng nhập. 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 ứng dụng của bạn, cách được khuyên dùng để biết trạng thái xác thực của người dùng là đặt trình quan sát trên đối tượng Auth . Sau đó, bạn có thể lấy thông tin hồ sơ cơ bản của người dùng từ đối tượng User . Xem Quản lý người dùng .

  • Trong Quy tắc bảo mật cơ sở dữ liệu thời gian thực và lưu trữ đám mây của Firebase, bạn có thể lấy ID người dùng duy nhất của người dùng đã đăng nhập từ biến auth và sử dụng nó để kiểm soát dữ liệu nào 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 mình bằng nhiều nhà cung cấp xác thực bằng cách liên kết thông tin xác thực của nhà cung cấp xác thực với tài khoản người dùng hiện có.

Để đăng xuất người dùng, hãy gọi signOut :

Web modular API

import { getAuth, signOut } from "firebase/auth";

const auth = getAuth();
signOut(auth).then(() => {
  // Sign-out successful.
}).catch((error) => {
  // An error happened.
});

Web namespaced API

firebase.auth().signOut().then(() => {
  // Sign-out successful.
}).catch((error) => {
  // An error happened.
});