Uwierzytelnij przez Apple z JavaScriptem

Możesz umożliwić użytkownikom uwierzytelnianie w Firebase za pomocą ich identyfikatorów Apple ID, korzystając z pakietu SDK Firebase do przeprowadzenia pełnego procesu logowania OAuth 2.0.

Zanim zaczniesz

Aby logować użytkowników przy użyciu urządzenia Apple, najpierw skonfiguruj funkcję Zaloguj się przez Apple w witrynie dla deweloperów Apple, a potem włącz Apple jako dostawcę logowania w swoim projekcie Firebase.

Dołącz do programu dla deweloperów Apple

Funkcja Zaloguj się przez Apple może skonfigurować tylko członkowie programu dla deweloperów Apple.

Skonfiguruj logowanie się przez Apple

Na stronie Apple Developers wykonaj te czynności:

  1. Powiąż witrynę z aplikacją w sposób opisany w pierwszej sekcji Konfigurowanie logowania się przez Apple w przeglądarce. Gdy pojawi się prośba, zarejestruj ten URL jako powrotny adres URL:

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

    Identyfikator projektu Firebase znajdziesz na stronie ustawień konsoli Firebase.

    Gdy skończysz, zanotuj nowy identyfikator usługi, który będzie Ci potrzebny w następnej sekcji.

  2. Utwórz klucz prywatny funkcji Zaloguj się przez Apple. W następnej sekcji będą Ci potrzebne nowy klucz prywatny i identyfikator klucza.
  3. Jeśli używasz dowolnej funkcji uwierzytelniania Firebase, która wysyła e-maile do użytkowników, w tym np. logowania się za pomocą linku przez e-maila, weryfikacji adresu e-mail czy unieważniania zmiany konta, skonfiguruj usługę prywatnego przekaźnika poczty e-mail firmy Apple i zarejestruj noreply@YOUR_FIREBASE_PROJECT_ID.firebaseapp.com (lub własną domenę szablonu e-maila), aby firma Apple mogła przekazywać e-maile wysyłane przez usługę Uwierzytelnianie Firebase na zanonimizowane adresy e-mail Apple.

Włącz Apple jako dostawcę logowania

  1. Dodaj Firebase do swojego projektu.
  2. W konsoli Firebase otwórz sekcję Uwierzytelnianie. Na karcie Metoda logowania włącz dostawcę Apple. Podaj identyfikator usługi utworzony w poprzedniej sekcji. Poza tym w sekcji Konfiguracja przepływu kodu OAuth podaj identyfikator zespołu Apple oraz klucz prywatny i identyfikator klucza utworzone w poprzedniej sekcji.

Zgodność z wymaganiami firmy Apple dotyczącymi zanonimizowanych danych

Zaloguj się przez Apple umożliwia anonimizację danych, w tym adresu e-mail, podczas logowania. Użytkownicy, którzy wybiorą tę opcję, mają adresy e-mail w domenie privaterelay.appleid.com. Gdy w swojej aplikacji korzystasz z funkcji Zaloguj się przez Apple, musisz przestrzegać wszystkich obowiązujących zasad dla deweloperów i warunków firmy Apple dotyczących tych zanonimizowanych identyfikatorów Apple.

Obejmuje to uzyskanie wymaganej zgody użytkownika przed powiązaniem danych osobowych umożliwiających bezpośrednią identyfikację z anonimowym identyfikatorem Apple ID. Gdy używasz uwierzytelniania Firebase, może to wiązać się z tymi działaniami:

  • Połącz adres e-mail z anonimowym identyfikatorem Apple ID lub odwrotnie.
  • Łączenie numeru telefonu z anonimowym identyfikatorem Apple ID i odwrotnie
  • Połącz nieanonimowe dane społecznościowe (Facebook, Google itp.) z anonimowym identyfikatorem Apple lub odwrotnie.

Powyższa lista nie jest wyczerpująca. Zapoznaj się z umową licencyjną programu Apple dla deweloperów w sekcji Subskrypcja na koncie dewelopera, aby upewnić się, że Twoja aplikacja spełnia wymagania Apple.

Zarejestruj się za pomocą pakietu SDK Firebase

Jeśli tworzysz aplikację internetową, najprostszym sposobem uwierzytelniania użytkowników w Firebase za pomocą ich kont Apple jest obsługa całego procesu logowania za pomocą pakietu Firebase JavaScript SDK.

Aby zalogować się za pomocą pakietu SDK Firebase JavaScript, wykonaj te czynności:

  1. Utwórz instancję OAuthProvider za pomocą odpowiedniego identyfikatora dostawcy apple.com.

    Web Modular API

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

    Interfejs API internetowej przestrzeni nazw

    var provider = new firebase.auth.OAuthProvider('apple.com');
  2. Opcjonalnie: określ dodatkowe zakresy OAuth 2.0 wykraczające poza domyślne, o które chcesz prosić dostawcę uwierzytelniania.

    Web Modular API

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

    Interfejs API internetowej przestrzeni nazw

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

    Gdy włączona jest opcja Jedno konto na adres e-mail, Firebase domyślnie prosi o zakresy adresów e-mail i nazw. Jeśli zmienisz to ustawienie na Wiele kont na adres e-mail, Firebase nie będzie żądać od Apple żadnych zakresów, chyba że je określisz.

  3. Opcjonalnie: jeśli chcesz wyświetlać ekran logowania Apple w języku innym niż angielski, ustaw parametr locale. Informacje o obsługiwanych regionach znajdziesz w dokumentacji logowania się przez Apple.

    Web Modular API

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

    Interfejs API internetowej przestrzeni nazw

    provider.setCustomParameters({
      // Localize the Apple authentication screen in French.
      locale: 'fr'
    });
  4. Uwierzytelniaj w Firebase za pomocą obiektu dostawcy OAuth. Możesz poprosić użytkowników o zalogowanie się za pomocą kont Apple przez otwarcie wyskakującego okienka lub przekierowanie na stronę logowania. Metoda przekierowania jest preferowana na urządzeniach mobilnych.

    • Aby zalogować się za pomocą wyskakującego okienka, zadzwoń pod numer 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);
      
          // ...
        });

      Interfejs API internetowej przestrzeni nazw

      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;
      
          // ...
        });
    • Aby zalogować się, przekierowując na stronę logowania, wywołaj signInWithRedirect():

    Jeśli korzystasz z tagów signInWithRedirect, linkWithRedirect lub reauthenticateWithRedirect, postępuj zgodnie ze sprawdzonymi metodami.

    Web Modular API

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

    Interfejs API internetowej przestrzeni nazw

    firebase.auth().signInWithRedirect(provider);

    Gdy użytkownik zaloguje się i wróci na stronę, wynik logowania możesz uzyskać, wywołując metodę 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);
    
        // ...
      });

    Interfejs API internetowej przestrzeni nazw

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

    Możesz w nim też wykrywać i poprawiać błędy. Listę kodów błędów znajdziesz w dokumentacji interfejsu API.

    W przeciwieństwie do innych dostawców obsługiwanych przez Uwierzytelnianie Firebase Apple nie udostępnia adresu URL zdjęcia.

    Oprócz tego, gdy użytkownik zdecyduje się nie udostępniać swojego adresu e-mail aplikacji, Apple udostępnia mu unikalny adres e-mail (w formie formularza xyz@privaterelay.appleid.com), który udostępnia aplikacji. Jeśli masz skonfigurowaną prywatną usługę przekaźnika, Apple przekazuje e-maile wysyłane na anonimowy adres na rzeczywisty adres użytkownika.

    Apple udostępnia aplikacjom informacje o użytkowniku, takie jak wyświetlana nazwa, tylko przy pierwszym logowaniu użytkownika. Zwykle Firebase przechowuje wyświetlaną nazwę przy pierwszym logowaniu się użytkownika w Apple. Możesz to uzyskać za pomocą firebase.auth().currentUser.displayName. Jeśli jednak zdarzyło Ci się logować użytkownika w aplikacji za pomocą usługi Apple bez użycia Firebase, Apple nie udostępni Firebase wyświetlanej nazwy użytkownika.

Ponowne uwierzytelnianie i łączenie kont

Tego samego wzorca można używać z metodami reauthenticateWithPopup() i reauthenticateWithRedirect(), które umożliwiają pobranie nowych danych logowania w przypadku operacji poufnych, które wymagają ostatniego logowania:

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

    // ...
  });

Interfejs API internetowej przestrzeni nazw

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;

    // ...
  });

Za pomocą linkWithPopup() i linkWithRedirect() możesz połączyć różnych dostawców tożsamości z istniejącymi kontami.

Pamiętaj, że firma Apple wymaga uzyskania wyraźnej zgody użytkowników przed połączeniem ich kont Apple z innymi danymi.

Aby np. połączyć konto na Facebooku z bieżącym kontem Firebase, użyj tokena dostępu uzyskanego po zalogowaniu użytkownika na Facebooku:

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

Interfejs API internetowej przestrzeni nazw

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

Uwierzytelnianie za pomocą Firebase w rozszerzeniu do Chrome

Jeśli tworzysz aplikację rozszerzenia do Chrome, zapoznaj się z przewodnikiem po dokumentach poza ekranem.

Uwaga: nadal musisz zweryfikować domenę niestandardową w Apple, podobnie jak w przypadku domyślnej domeny firebaseapp.com:

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

Unieważnienie tokena

Firma Apple wymaga, aby aplikacje, które umożliwiają tworzenie kont, muszą umożliwiać użytkownikom zainicjowanie usunięcia konta z poziomu aplikacji, zgodnie z opisem w wytycznych dotyczących zamieszczania opinii w sklepie z aplikacjami.

Aby spełnić to wymaganie, wykonaj następujące czynności:

  1. Upewnij się, że wypełniono sekcje Identyfikator usług i Konfiguracja przepływu kodu OAuth w konfiguracji dostawcy funkcji Zaloguj się przez Apple, jak opisano w sekcji Konfigurowanie logowania przez Apple.

  2. Firebase nie przechowuje tokenów użytkowników tworzonych za pomocą funkcji Zaloguj się przez Apple, dlatego przed unieważnieniem tokena i usunięciem konta musisz poprosić użytkownika o ponowne zalogowanie się.

    Następnie uzyskaj token dostępu Apple OAuth ze strony OAuthCredential i użyj go do wywołania metody revokeAccessToken(auth, token) w celu unieważnienia tokena dostępu 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. Na koniec usuń konto użytkownika (i wszystkie powiązane z nim dane).

Zaawansowane: uwierzytelnianie za pomocą Firebase w Node.js

Aby uwierzytelnić się w Firebase w aplikacji Node.js:

  1. Zaloguj użytkownika na jego konto Apple i pobierz jego token Apple ID. Możesz to osiągnąć na kilka sposobów. Jeśli na przykład aplikacja Node.js ma interfejs przeglądarki:

    1. W backendzie wygeneruj losowy ciąg znaków („jednorazowy”) i oblicz jego hasz SHA256. Liczba jednorazowa to jednorazowa wartość służąca do walidacji pojedynczej podróży w obie strony między backendem a serwerami uwierzytelniania 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');

      Interfejs API internetowej przestrzeni nazw

      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. Na stronie logowania podaj zaszyfrowaną wartość jednorazową w konfiguracji funkcji Zaloguj się przez Apple:

      <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. Pobierz token Apple ID ze strony serwera odpowiedzi POST:

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

    Zobacz też Konfigurowanie strony internetowej pod kątem logowania przez Apple.

  2. Gdy uzyskasz token Apple ID użytkownika, użyj go do utworzenia obiektu danych logowania, a następnie zaloguj użytkownika za pomocą danych logowania:

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

    Interfejs API internetowej przestrzeni nazw

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

Dalsze kroki

Gdy użytkownik loguje się po raz pierwszy, tworzone jest nowe konto użytkownika, które jest łączone z danymi logowania (nazwa użytkownika i hasło, numer telefonu lub informacje o dostawcy uwierzytelniania). Nowe konto jest przechowywane w ramach Twojego projektu Firebase i może być używane do identyfikowania użytkowników we wszystkich aplikacjach w Twoim projekcie niezależnie od tego, jak się on loguje.

  • Zalecanym sposobem na poznanie stanu uwierzytelniania użytkownika w aplikacjach jest ustawienie obserwatora w obiekcie Auth. Dzięki temu można uzyskać podstawowe informacje o profilu użytkownika z obiektu User. Zobacz Zarządzanie użytkownikami.

  • W regułach zabezpieczeń Bazy danych czasu rzeczywistego Firebase i Cloud Storage możesz pobrać ze zmiennej auth unikalny identyfikator użytkownika zalogowanego użytkownika i użyć go do kontrolowania, do jakich danych użytkownik ma dostęp.

Możesz zezwolić użytkownikom na logowanie się w aplikacji przy użyciu różnych dostawców uwierzytelniania, łącząc dane logowania dostawcy uwierzytelniania z istniejącym kontem użytkownika.

Aby wylogować użytkownika, wywołaj signOut:

Web Modular API

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

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

Interfejs API internetowej przestrzeni nazw

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