Вы можете разрешить своим пользователям проходить аутентификацию в Firebase с использованием их Apple ID, используя Firebase SDK для реализации сквозного процесса входа OAuth 2.0.
Прежде чем начать
Чтобы выполнить вход пользователей с помощью Apple, сначала настройте функцию «Вход с Apple» на сайте разработчиков Apple, а затем включите Apple в качестве поставщика входа для вашего проекта Firebase.
Присоединяйтесь к программе разработчиков Apple
Функцию «Войти с Apple» могут настроить только участники программы разработчиков Apple .
Настроить вход с Apple
На сайте разработчиков Apple выполните следующие действия:
Свяжите свой веб-сайт с приложением, как описано в первом разделе статьи «Настройка входа с Apple для веб-сайта» . При появлении запроса зарегистрируйте следующий 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 откройте раздел «Аутентификация» . На вкладке «Метод входа» включите поставщика Apple . Укажите идентификатор сервиса, созданный в предыдущем разделе. Кроме того, в разделе «Конфигурация потока кода OAuth» укажите идентификатор вашей команды Apple Team ID, а также закрытый ключ и идентификатор ключа, созданные в предыдущем разделе.
Соблюдайте требования Apple к анонимным данным
Функция «Войти с Apple» предоставляет пользователям возможность анонимизировать свои данные, включая адрес электронной почты, при входе в систему. Адреса электронной почты пользователей, выбравших эту опцию, находятся в домене privaterelay.appleid.com
. При использовании функции «Войти с Apple» в вашем приложении вы должны соблюдать все применимые политики разработчиков или условия Apple в отношении этих анонимизированных идентификаторов Apple ID.
Это включает получение любого необходимого согласия пользователя перед связыванием какой-либо персональной информации, позволяющей идентифицировать пользователя, с анонимизированным Apple ID. При использовании аутентификации Firebase это может включать следующие действия:
- Свяжите адрес электронной почты с анонимным Apple ID и наоборот.
- Привязать номер телефона к анонимному Apple ID и наоборот
- Свяжите неанонимные учетные данные социальной сети (Facebook, Google и т. д.) с анонимным Apple ID или наоборот.
Приведённый выше список не является исчерпывающим. Чтобы убедиться, что ваше приложение соответствует требованиям Apple, ознакомьтесь с лицензионным соглашением программы Apple Developer Program в разделе «Участие» вашей учётной записи разработчика.
Управляйте процессом входа с помощью Firebase SDK
Если вы создаете веб-приложение, самый простой способ аутентификации пользователей в Firebase с использованием их учетных записей 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. Его можно получить с помощью
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, см. руководство по Offscreen Documents .
Обратите внимание, что вам все равно необходимо подтвердить пользовательский домен в Apple, аналогично домену по умолчанию firebaseapp.com:
http://auth.custom.example.com/.well-known/apple-developer-domain-association.txt
Отзыв токена
Apple требует, чтобы приложения, поддерживающие создание учетных записей, позволяли пользователям инициировать удаление своих учетных записей внутри приложения, как описано в Руководстве по обзору App Store.
Для выполнения этого требования выполните следующие шаги:
Убедитесь, что вы заполнили раздел конфигурации идентификатора служб и потока кода OAuth в конфигурации поставщика входа с помощью Apple, как описано в разделе «Настройка входа с помощью Apple» .
Поскольку Firebase не сохраняет токены пользователей при создании учетных записей с помощью функции «Войти с Apple», вам необходимо попросить пользователя снова войти в систему, прежде чем отозвать его токен и удалить учетную запись.
Затем получите токен доступа Apple OAuth из
OAuthCredential
и используйте его для вызоваrevokeAccessToken(auth, token)
чтобы отозвать токен доступа 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. // ... }); });
Наконец, удалите учетную запись пользователя (и все связанные с ней данные).
Дополнительно: аутентификация с помощью Firebase в Node.js
Для аутентификации с помощью Firebase в приложении Node.js:
Авторизуйте пользователя, используя его учётную запись Apple, и получите токен Apple ID. Это можно сделать несколькими способами. Например, если ваше приложение Node.js имеет браузерный интерфейс:
На вашем сервере сгенерируйте случайную строку (nonce) и вычислите её хеш SHA-256. Nonce — это одноразовое значение, используемое для проверки одного кругового пути между вашим сервером и серверами авторизации 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 из ответа аутентификации 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). } });
См. также раздел Настройка веб-страницы для входа с помощью 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. });