Вы можете разрешить пользователям выполнять аутентификацию в Firebase с помощью Apple ID, используя Firebase SDK для реализации сквозного процесса входа OAuth 2.0.
Подготовка
Чтобы пользователи могли входить в систему с помощью Apple, сначала настройте функцию "Войти с Apple" на сайте для разработчиков Apple, а затем включите Apple в качестве поставщика учетных данных для входа в проект Firebase.
Как присоединиться к программе Apple Developer Program
Настроить функцию "Войти с Apple" могут только участники программы Apple Developer Program.
Как настроить вход через аккаунт Apple
На сайте Apple Developer выполните следующие действия:
-
Свяжите сайт с приложением, как описано в первом разделе статьи Настройка входа с Apple ID для сайта. Когда появится запрос, зарегистрируйте следующий URL в качестве URL возврата:
https://YOUR_FIREBASE_PROJECT_ID.firebaseapp.com/__/auth/handler
Идентификатор проекта Firebase можно найти в консоли Firebase на вкладке
Настройки > Общие.Запишите идентификатор сервиса, который вы только что создали. Он понадобится вам в следующем разделе.
- Создайте закрытый ключ для функции "Войти с Apple". В следующем разделе вам понадобятся новый закрытый ключ и идентификатор ключа.
-
Если вы используете какие-либо функции Firebase Authentication, которые отправляют электронные письма пользователям, включая вход по ссылке в электронном письме, подтверждение адреса электронной почты, отмену изменения аккаунта и другие, настройте службу ретрансляции частной электронной почты Apple и зарегистрируйте
noreply@YOUR_FIREBASE_PROJECT_ID.firebaseapp.com(или ваш настроенный домен шаблона электронной почты), чтобы Apple могла ретранслировать электронные письма, отправленные Firebase Authentication, на анонимные адреса электронной почты Apple.
Как включить Apple в качестве поставщика идентификационной информации
- Добавьте Firebase в проект.
- В консоли Firebase выберите Безопасность > Аутентификация.
- На вкладке Sign-in method (Способ входа) включите поставщика входа Apple. Укажите идентификатор сервиса, созданный в предыдущем разделе. В разделе OAuth code flow configuration (Конфигурация потока кода OAuth) укажите идентификатор команды Apple, а также закрытый ключ и его идентификатор, созданные в предыдущем разделе.
Соблюдайте требования Apple к анонимизированным данным
При входе с Apple ID пользователи могут анонимизировать свои данные, в том числе адрес электронной почты. Пользователи, которые выберут этот вариант, получат адреса электронной почты с доменом privaterelay.appleid.com. При использовании функции "Войти с Apple" в приложении вы должны соблюдать все применимые правила для разработчиков и условия использования Apple, касающиеся анонимизированных идентификаторов Apple.
В частности, вы должны получить согласие пользователя, прежде чем связывать какую-либо информацию, позволяющую идентифицировать личность, с анонимным идентификатором Apple ID. При использовании Firebase Authentication могут выполняться следующие действия:
- Связывать адрес электронной почты с анонимным Apple ID или наоборот.
- Как связать номер телефона с анонимизированным Apple ID или наоборот
- Связывать неанонимные учетные данные социальных сетей (Facebook, Google и т. д.) с анонимизированным Apple ID или наоборот.
Этот список не является исчерпывающим. Чтобы убедиться, что ваше приложение соответствует требованиям Apple, ознакомьтесь с лицензионным соглашением Apple Developer Program в разделе Membership (Участие) аккаунта разработчика.
Как управлять процессом входа с помощью Firebase SDK
Если вы создаете веб-приложение, проще всего реализовать аутентификацию пользователей с помощью аккаунтов Apple, используя Firebase JavaScript SDK.
Чтобы настроить процесс входа с помощью Firebase JavaScript SDK, выполните следующие действия:
Создайте экземпляр OAuthProvider, используя соответствующий идентификатор поставщика apple.com.
Web
import { OAuthProvider } from "firebase/auth"; const provider = new OAuthProvider('apple.com');
Web
var provider = new firebase.auth.OAuthProvider('apple.com');
Необязательно. Укажите дополнительные области действия OAuth 2.0, которые вы хотите запросить у поставщика аутентификации.
Web
provider.addScope('email'); provider.addScope('name');
Web
provider.addScope('email'); provider.addScope('name');
По умолчанию, когда включен параметр Один аккаунт на адрес электронной почты, Firebase запрашивает области действия для адреса электронной почты и имени. Если вы выберете вариант Несколько аккаунтов на один адрес электронной почты, Firebase не будет запрашивать у Apple области действия, если вы не укажете их.
Необязательно. Если вы хотите, чтобы экран входа в аккаунт Apple отображался не на английском языке, задайте параметр
locale. Поддерживаемые языки перечислены в документации по функции "Войти с Apple".Web
provider.setCustomParameters({ // Localize the Apple authentication screen in French. locale: 'fr' });
Web
provider.setCustomParameters({ // Localize the Apple authentication screen in French. locale: 'fr' });
Выполните аутентификацию в Firebase, используя объект поставщика OAuth. Вы можете предложить пользователям войти в систему, используя свои аккаунты Apple, открыв всплывающее окно или перенаправив их на страницу входа. На мобильных устройствах рекомендуется использовать метод переадресации.
Чтобы войти в систему с помощью всплывающего окна, вызовите функцию
signInWithPopup():Web
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
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; // ... });
Чтобы войти в аккаунт, перейдя на страницу входа, вызовите функцию
signInWithRedirect():
При использовании
signInWithRedirect,linkWithRedirectилиreauthenticateWithRedirectследуйте рекомендациям.Web
import { getAuth, signInWithRedirect } from "firebase/auth"; const auth = getAuth(); signInWithRedirect(auth, provider);
Web
firebase.auth().signInWithRedirect(provider);
После того как пользователь выполнит вход и вернется на страницу, вы можете получить результат входа, вызвав
getRedirectResult():Web
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
// 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; // ... });
Здесь же можно отслеживать и обрабатывать ошибки. Список кодов ошибок приведен в справочной документации по API.
В отличие от других поставщиков, поддерживаемых Firebase Auth, Apple не предоставляет URL фотографии.
Если пользователь не хочет делиться своим адресом электронной почты с приложением, Apple предоставляет ему уникальный адрес (в формате
xyz@privaterelay.appleid.com), который передается приложению. Если вы настроили сервис ретрансляции частных электронных адресов, Apple пересылает письма, отправленные на анонимный адрес, на настоящий адрес пользователя.Apple передает приложениям информацию о пользователе, например отображаемое имя, только при первом входе. Обычно Firebase сохраняет отображаемое имя при первом входе пользователя с помощью Apple ID. Получить его можно с помощью
firebase.auth().currentUser.displayName. Однако если вы ранее использовали Apple для входа пользователя в приложение без Firebase, Apple не предоставит Firebase отображаемое имя пользователя.
Повторная аутентификация и связывание аккаунтов
Аналогичный шаблон можно использовать с reauthenticateWithPopup() и reauthenticateWithRedirect(), чтобы получать новые учетные данные для конфиденциальных операций, требующих недавнего входа в аккаунт:
Web
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
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; // ... });
Кроме того, вы можете использовать linkWithPopup() и linkWithRedirect(), чтобы связать разных поставщиков идентификационной информации с существующими аккаунтами.
Обратите внимание, что Apple требует получать явное согласие пользователей, прежде чем связывать их аккаунты Apple с другими данными.
Например, чтобы связать аккаунт Facebook с текущим аккаунтом Firebase, используйте токен доступа, полученный при входе пользователя в Facebook:
Web
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
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. });
Как пройти аутентификацию с помощью Firebase в расширении Chrome
Если вы создаете расширение Chrome, ознакомьтесь с руководством по документам вне экрана.
Обратите внимание, что вам все равно нужно будет подтвердить пользовательский домен в Apple, как и домен firebaseapp.com по умолчанию:
http://auth.custom.example.com/.well-known/apple-developer-domain-association.txt
Отзыв токена
Согласно требованиям App Store, если в приложении можно создать аккаунт, то в нем должна быть и возможность запросить удаление аккаунта.
Чтобы выполнить это требование, сделайте следующее:
Убедитесь, что вы заполнили разделы Services ID (Идентификатор сервисов) и OAuth code flow configuration (Конфигурация потока кода OAuth) в настройках поставщика Sign in with Apple, как описано в разделе Настройка Sign in with Apple.
Поскольку Firebase не хранит токены пользователей, созданных с помощью функции "Войти с Apple", вам необходимо попросить пользователя войти в систему ещё раз, прежде чем отзывать его токен и удалять аккаунт.
Затем получите токен доступа OAuth от Apple из
OAuthCredentialи используйте его, чтобы вызватьrevokeAccessToken(auth, token)и отозвать токен доступа OAuth от Apple.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. // ... }); });Наконец, удалите аккаунт пользователя (и все связанные с ним данные).
Для опытных пользователей: аутентификация с помощью Firebase в Node.js
Чтобы выполнить аутентификацию с помощью Firebase в приложении Node.js, сделайте следующее:
Выполните вход пользователя с помощью его аккаунта Apple и получите токен Apple ID пользователя. Это можно сделать несколькими способами. Например, если у вашего приложения Node.js есть интерфейс браузера:
На сервере создайте случайную строку (одноразовый код) и вычислите ее хеш SHA256. Одноразовый код – это значение, которое используется один раз для проверки одного цикла обмена данными между вашим сервером и серверами аутентификации Apple.
Web
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
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');
На странице входа укажите хешированный одноразовый код в конфигурации функции "Войти с 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>Получите токен Apple ID из ответа на 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). } });
Также ознакомьтесь со статьей Configuring Your Webpage for Sign In with Apple (Как настроить веб-страницу для входа с Apple).
Получив токен Apple ID пользователя, используйте его для создания объекта Credential, а затем выполните вход пользователя с помощью этих учетных данных:
Web
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
// 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); });
Дальнейшие действия
После первого входа пользователя создается новый аккаунт, который связывается с учетными данными, использованными для входа (именем пользователя и паролем, номером телефона или информацией от поставщика аутентификации). Этот аккаунт сохраняется в проекте Firebase и может использоваться для идентификации пользователя во всех приложениях проекта, независимо от того, как пользователь входит в систему.
-
В приложениях рекомендуется отслеживать статус аутентификации пользователя, установив наблюдатель для объекта
Auth. После этого вы сможете получить основную информацию профиля пользователя из объектаUser. Подробнее о том, как управлять пользователями… В Firebase Realtime Database и Cloud Storage правилах безопасности можно получить уникальный идентификатор пользователя, выполнившего вход, из переменной
authи использовать его, чтобы контролировать, к каким данным у пользователя есть доступ.
Вы можете разрешить пользователям входить в приложение с помощью нескольких поставщиков аутентификации, связав учетные данные поставщика аутентификации с существующим аккаунтом пользователя.
Чтобы выйти из аккаунта пользователя, вызовите функцию
signOut:
Web
import { getAuth, signOut } from "firebase/auth"; const auth = getAuth(); signOut(auth).then(() => { // Sign-out successful. }).catch((error) => { // An error happened. });
Web
firebase.auth().signOut().then(() => { // Sign-out successful. }).catch((error) => { // An error happened. });