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 với JavaScript

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 để dự án của bạn .
  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

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ộ quy trình đăng nhập bằng SDK JavaScript của Firebase.

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

  1. Tạo một thể hiện của một OAuthProvider sử dụng các nhà cung cấp ID tương ứng apple.com.

    Phiên bản web 9

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

    Phiên bản web 8

    var provider = new firebase.auth.OAuthProvider('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.

    Phiên bản web 9

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

    Phiên bản web 8

    provider.addScope('email');
    provider.addScope('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ợ.

    Phiên bản web 9

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

    Phiên bản web 8

    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 của mình đă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 chuyển hướng đến trang đăng nhập. Phương pháp chuyển hướng được ưu tiên trên thiết bị di động.

    • Để đăng nhập với một cửa sổ pop-up, hãy gọi signInWithPopup() :

      Phiên bản web 9

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

      Phiên bản web 8

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

      Phiên bản web 9

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

      Phiên bản web 8

      firebase.auth().signInWithRedirect(provider);

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

      Phiên bản web 9

      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.email;
          // The credential that was used.
          const credential = OAuthProvider.credentialFromError(error);
      
          // ...
        });

      Phiên bản web 8

      // 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;
      
            // ...
          }
          // 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ể nắm bắt và xử lý lỗi. Đối với một danh sách các mã lỗi, 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 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 firebase.auth().currentUser.displayName . Tuy nhiên, nếu trước đây bạn đã sử dụng Apple để đăng nhập một 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 reauthenticateWithPopup()reauthenticateWithRedirect() , 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:

Phiên bản web 9

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.email;
    // The credential that was used.
    const credential = OAuthProvider.credentialFromError(error);

    // ...
  });

Phiên bản web 8

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;

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

Phiên bản web 9

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

Phiên bản web 8

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 tạo ứng dụng tiện ích mở rộng Chrome, bạn phải thêm ID tiện ích mở rộng Chrome của mình:

  1. Mở dự án của bạn trong căn cứ hỏa lực console .
  2. Trong phần xác thực, mở Trang đăng nhập phương pháp.
  3. Thêm một URI như sau vào danh sách các ủy quyền tên miền:
    chrome-extension://CHROME_EXTENSION_ID

Chỉ hoạt động cửa sổ bật lên ( signInWithPopup , linkWithPopup , và reauthenticateWithPopup ) có sẵn để mở rộng Chrome, như phần mở rộng Chrome không thể sử dụng HTTP chuyển hướng. Bạn nên gọi các phương thức này từ tập lệnh trang nền hơn là cửa sổ bật lên hành động của trình duyệt, vì cửa sổ bật lên xác thực sẽ hủy cửa sổ bật lên hành động của trình duyệt. Các phương pháp cửa sổ bật lên chỉ có thể được sử dụng trong phần mở rộng sử dụng Manifest V2 . Các phiên bản mới hơn Manifest V3 chỉ cho phép các kịch bản nền trong các hình thức của người lao động dịch vụ, trong đó không thể thực hiện các thao tác bật lên ở tất cả.

Trong tệp giúp việc biểu hiện phần mở rộng của Chrome của bạn chắc chắn rằng bạn thêm https://apis.google.com URL đến content_security_policy allowlist.

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

Nâng cao: Xác thực với 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 ID Apple của người dùng. Bạn có thể thực hiện điều này bằng một số cách. Ví dụ: nếu ứng dụng Node.js của bạn có giao diện người dùng là trình duyệt:

    1. Trên phần phụ trợ của bạn, hãy 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 khứ hồi giữa máy chủ phụ trợ của bạn và máy chủ xác thực của Apple.

      Phiên bản web 9

      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.substr(0, length);
      };
      
      const unhashedNonce = generateNonce(10);
      
      // SHA256-hashed nonce in hex
      const hashedNonceHex = crypto.createHash('sha256')
        .update(unhashedNonce).digest().toString('hex');

      Phiên bản web 8

      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.substr(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 mã 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 ID Apple từ phía máy chủ phản hồi xác thực POSTed:

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

    Xem thêm Cấu hình trang web của bạn để đăng nhập với Apple .

  2. Sau khi bạn nhận được mã thông báo ID Apple 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 người dùng bằng thông tin xác thực:

    Phiên bản web 9

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

    Phiên bản web 8

    // 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 đă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, cách đề nghị để biết tình trạng auth của người dùng của bạn là để thiết lập một quan sát viên trên Auth đối tượng. Sau đó bạn có thể nhận được thông tin hồ sơ cơ bản của người dùng từ các User đố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 :

Phiên bản web 9

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

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

Phiên bản web 8

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