Вы можете позволить своим пользователям проходить аутентификацию в Firebase, используя свой Apple ID, используя Firebase SDK для выполнения сквозного процесса входа OAuth 2.0.
Прежде чем вы начнете
Чтобы входить в систему с помощью Apple, сначала настройте вход с помощью Apple на сайте разработчиков Apple, а затем включите Apple в качестве поставщика входа для вашего проекта Firebase.
Присоединяйтесь к программе Apple для разработчиков
Вход с помощью Apple может быть настроен только участниками программы Apple Developer Program .
Настройка входа с помощью Apple
Apple Sign In должен быть включен и правильно настроен в вашем проекте Firebase. Конфигурация зависит от платформ Android и Apple. Прежде чем продолжить, следуйте разделу «Настройка входа с помощью Apple» в руководствах по платформам Apple и/или Android .Включить Apple в качестве поставщика услуг входа
- В консоли Firebase откройте раздел Auth . На вкладке Способ входа включите поставщика Apple .
- Настройте параметры поставщика Apple Sign-in:
- Если вы развертываете приложение только на платформах Apple, поля «Идентификатор службы», «Идентификатор команды Apple», «Закрытый ключ» и «Идентификатор ключа» можно оставить пустыми.
- Для поддержки на устройствах Android:
- Добавьте Firebase в свой Android-проект . Обязательно зарегистрируйте подпись SHA-1 вашего приложения при настройке приложения в консоли Firebase.
- В консоли Firebase откройте раздел Auth . На вкладке Способ входа включите поставщика Apple . Укажите идентификатор службы, созданный в предыдущем разделе. Кроме того, в разделе конфигурации потока кода OAuth укажите свой идентификатор Apple Team, а также закрытый ключ и идентификатор ключа, созданные в предыдущем разделе.
Соблюдайте требования Apple к анонимным данным
Войти с Apple дает пользователям возможность анонимизировать свои данные, включая адрес электронной почты, при входе в систему. Пользователи, которые выбирают этот вариант, имеют адреса электронной почты с доменом privaterelay.appleid.com
. Когда вы используете «Войти через Apple» в своем приложении, вы должны соблюдать все применимые политики или условия Apple для разработчиков в отношении этих анонимных идентификаторов Apple ID.
Это включает в себя получение любого необходимого согласия пользователя, прежде чем вы свяжете какую-либо личную информацию, непосредственно идентифицирующую личность, с анонимным Apple ID. При использовании Firebase Authentication это может включать следующие действия:
- Свяжите адрес электронной почты с анонимным Apple ID или наоборот.
- Привязать номер телефона к анонимному Apple ID или наоборот
- Свяжите неанонимные социальные учетные данные (Facebook, Google и т. д.) с анонимным Apple ID или наоборот.
Приведенный выше список не является исчерпывающим. См. Лицензионное соглашение программы Apple Developer Program в разделе «Членство» вашей учетной записи разработчика, чтобы убедиться, что ваше приложение соответствует требованиям Apple.
Доступ к классу firebase::auth::Auth
Класс Auth
является шлюзом для всех вызовов API.- Добавьте файлы заголовков Auth и App:
#include "firebase/app.h" #include "firebase/auth.h"
- В коде инициализации создайте класс
firebase::App
.#if defined(__ANDROID__) firebase::App* app = firebase::App::Create(firebase::AppOptions(), my_jni_env, my_activity); #else firebase::App* app = firebase::App::Create(firebase::AppOptions()); #endif // defined(__ANDROID__)
- Получите класс
firebase::auth::Auth
для вашегоfirebase::App
. МеждуApp
иAuth
существует однозначное соответствие.firebase::auth::Auth* auth = firebase::auth::Auth::GetAuth(app);
Обработка процесса входа с помощью Firebase SDK
Процесс входа в систему с Apple различается на платформах Apple и Android.
На платформах Apple
Аутентифицируйте своих пользователей с помощью Firebase с помощью Apple Sign In Objective-C SDK, вызванного из вашего кода C++.
Для каждого запроса на вход создавайте случайную строку — «одноразовый номер», — которую вы будете использовать, чтобы убедиться, что токен идентификатора, который вы получаете, был предоставлен именно в ответ на запрос проверки подлинности вашего приложения. Этот шаг важен для предотвращения повторных атак.
- (NSString *)randomNonce:(NSInteger)length { NSAssert(length > 0, @"Expected nonce to have positive length"); NSString *characterSet = @"0123456789ABCDEFGHIJKLMNOPQRSTUVXYZabcdefghijklmnopqrstuvwxyz-._"; NSMutableString *result = [NSMutableString string]; NSInteger remainingLength = length; while (remainingLength > 0) { NSMutableArray *randoms = [NSMutableArray arrayWithCapacity:16]; for (NSInteger i = 0; i < 16; i++) { uint8_t random = 0; int errorCode = SecRandomCopyBytes(kSecRandomDefault, 1, &random); NSAssert(errorCode == errSecSuccess, @"Unable to generate nonce: OSStatus %i", errorCode); [randoms addObject:@(random)]; } for (NSNumber *random in randoms) { if (remainingLength == 0) { break; } if (random.unsignedIntValue < characterSet.length) { unichar character = [characterSet characterAtIndex:random.unsignedIntValue]; [result appendFormat:@"%C", character]; remainingLength--; } } } }
Вы отправите хэш SHA256 одноразового номера вместе с запросом на вход, который Apple передаст без изменений в ответе. Firebase проверяет ответ, хэшируя исходный одноразовый номер и сравнивая его со значением, переданным Apple.
Запустите процесс входа Apple, включив в свой запрос хэш SHA256 одноразового номера и класс делегата, который будет обрабатывать ответ Apple (см. следующий шаг):
- (void)startSignInWithAppleFlow { NSString *nonce = [self randomNonce:32]; self.currentNonce = nonce; ASAuthorizationAppleIDProvider *appleIDProvider = [[ASAuthorizationAppleIDProvider alloc] init]; ASAuthorizationAppleIDRequest *request = [appleIDProvider createRequest]; request.requestedScopes = @[ASAuthorizationScopeFullName, ASAuthorizationScopeEmail]; request.nonce = [self stringBySha256HashingString:nonce]; ASAuthorizationController *authorizationController = [[ASAuthorizationController alloc] initWithAuthorizationRequests:@[request]]; authorizationController.delegate = self; authorizationController.presentationContextProvider = self; [authorizationController performRequests]; } - (NSString *)stringBySha256HashingString:(NSString *)input { const char *string = [input UTF8String]; unsigned char result[CC_SHA256_DIGEST_LENGTH]; CC_SHA256(string, (CC_LONG)strlen(string), result); NSMutableString *hashed = [NSMutableString stringWithCapacity:CC_SHA256_DIGEST_LENGTH * 2]; for (NSInteger i = 0; i < CC_SHA256_DIGEST_LENGTH; i++) { [hashed appendFormat:@"%02x", result[i]]; } return hashed; }
Обработайте ответ Apple в своей реализации ASAuthorizationControllerDelegate`. Если вход прошел успешно, используйте токен ID из ответа Apple с нехешированным одноразовым номером для аутентификации в Firebase:
- (void)authorizationController:(ASAuthorizationController *)controller didCompleteWithAuthorization:(ASAuthorization *)authorization API_AVAILABLE(ios(13.0)) { if ([authorization.credential isKindOfClass:[ASAuthorizationAppleIDCredential class]]) { ASAuthorizationAppleIDCredential *appleIDCredential = authorization.credential; NSString *rawNonce = self.currentNonce; NSAssert(rawNonce != nil, @"Invalid state: A login callback was received, but no login request was sent."); if (appleIDCredential.identityToken == nil) { NSLog(@"Unable to fetch identity token."); return; } NSString *idToken = [[NSString alloc] initWithData:appleIDCredential.identityToken encoding:NSUTF8StringEncoding]; if (idToken == nil) { NSLog(@"Unable to serialize id token from data: %@", appleIDCredential.identityToken); } }
Используйте полученную строку токена и исходный одноразовый номер, чтобы создать учетные данные Firebase и войти в Firebase.
firebase::auth::OAuthProvider::GetCredential( /*provider_id=*/"apple.com", token, nonce, /*access_token=*/nullptr); firebase::Future<firebase::auth::AuthResult> result = auth->SignInAndRetrieveDataWithCredential(credential);
Тот же шаблон можно использовать с
Reauthenticate
, который можно использовать для получения новых учетных данных для конфиденциальных операций, требующих недавнего входа в систему.firebase::Future<firebase::auth::AuthResult> result = user->Reauthenticate(credential);
Тот же шаблон можно использовать для привязки учетной записи к Apple Sign In. Однако вы можете столкнуться с ошибкой, когда существующая учетная запись Firebase уже связана с учетной записью Apple, с которой вы пытаетесь связать. Когда это произойдет, будущее вернет статус
kAuthErrorCredentialAlreadyInUse
, аAuthResult
может содержать действительныеcredential
. Эти учетные данные можно использовать для входа в учетную запись, связанную с Apple, с помощьюSignInAndRetrieveDataWithCredential
без необходимости создания другого токена входа Apple и одноразового номера.firebase::Future<firebase::auth::AuthResult> link_result = auth->current_user().LinkWithCredential(credential); // To keep example simple, wait on the current thread until call completes. while (link_result.status() == firebase::kFutureStatusPending) { Wait(100); } // Determine the result of the link attempt if (link_result.error() == firebase::auth::kAuthErrorNone) { // user linked correctly. } else if (link_result.error() == firebase::auth::kAuthErrorCredentialAlreadyInUse && link_result.result() ->additional_user_info.updated_credential.is_valid()) { // Sign In with the new credential firebase::Future<firebase::auth::AuthResult> result = auth->SignInAndRetrieveDataWithCredential( link_result.result()->additional_user_info.updated_credential); } else { // Another link error occurred. }
На Android
На Android аутентифицируйте своих пользователей с помощью Firebase, интегрировав универсальный веб-вход OAuth в свое приложение с помощью Firebase SDK для выполнения сквозного процесса входа.
Чтобы обработать процесс входа с помощью Firebase SDK, выполните следующие действия:
Создайте экземпляр
FederatedOAuthProviderData
, настроенный с идентификатором поставщика, подходящим для Apple.firebase::auth::FederatedOAuthProviderData provider_data("apple.com");
Необязательно: укажите дополнительные области действия OAuth 2.0 помимо значений по умолчанию, которые вы хотите запросить у поставщика проверки подлинности.
provider_data.scopes.push_back("email"); provider_data.scopes.push_back("name");
Необязательно: если вы хотите, чтобы экран входа в систему Apple отображался на языке, отличном от английского, установите параметр
locale
. Информацию о поддерживаемых языковых стандартах см. в документации «Вход с помощью Apple» .// Localize to French. provider_data.custom_parameters["language"] = "fr"; ```
После настройки данных поставщика используйте их для создания FederatedOAuthProvider.
// Construct a FederatedOAuthProvider for use in Auth methods. firebase::auth::FederatedOAuthProvider provider(provider_data);
Выполните аутентификацию в Firebase, используя объект поставщика аутентификации. Обратите внимание, что в отличие от других операций FirebaseAuth, эта операция возьмет на себя управление вашим пользовательским интерфейсом, открыв веб-представление, в котором пользователь может ввести свои учетные данные.
Чтобы запустить процесс входа, вызовите
signInWithProvider
:firebase::Future<firebase::auth::AuthResult> result = auth->SignInWithProvider(provider_data);
Затем ваше приложение может ожидать или зарегистрировать обратный вызов на Future .
Тот же шаблон можно использовать с
ReauthenticateWithProvider
, который можно использовать для получения новых учетных данных для конфиденциальных операций, требующих недавнего входа в систему.firebase::Future<firebase::auth::AuthResult> result = user.ReauthenticateWithProvider(provider_data);
Затем ваше приложение может ожидать или зарегистрировать обратный вызов на Future .
Кроме того, вы можете использовать
LinkWithCredential()
для привязки различных поставщиков удостоверений к существующим учетным записям.Обратите внимание, что Apple требует, чтобы вы получили явное согласие пользователей, прежде чем связать их учетные записи Apple с другими данными.
Например, чтобы связать учетную запись Facebook с текущей учетной записью Firebase, используйте токен доступа, полученный при входе пользователя в Facebook:
// Initialize a Facebook credential with a Facebook access token. AuthCredential credential = firebase::auth::FacebookAuthProvider.getCredential(token); // Assuming the current user is an Apple user linking a Facebook provider. firebase::Future<firebase::auth::AuthResult> result = auth.current_user().LinkWithCredential(credential);
Войти с помощью Apple Notes
В отличие от других поставщиков, поддерживаемых Firebase Auth, Apple не предоставляет URL-адрес фотографии.
Кроме того, когда пользователь решает не делиться своей электронной почтой с приложением, Apple предоставляет уникальный адрес электронной почты для этого пользователя (в форме xyz@privaterelay.appleid.com
), который он использует совместно с вашим приложением. Если вы настроили частную службу ретрансляции электронной почты, Apple перенаправляет электронные письма, отправленные на анонимный адрес, на реальный адрес электронной почты пользователя.
Apple передает информацию о пользователе, такую как отображаемое имя, приложениям только при первом входе пользователя в систему. Обычно Firebase сохраняет отображаемое имя при первом входе пользователя в Apple, которое вы можете получить с помощью current_user().display_name()
. Однако если вы ранее использовали Apple для входа пользователя в приложение без использования Firebase, Apple не предоставит Firebase отображаемое имя пользователя.
Следующие шаги
После того, как пользователь входит в систему в первый раз, создается новая учетная запись пользователя и связывается с учетными данными, т. е. с именем пользователя и паролем, номером телефона или информацией о поставщике проверки подлинности, с которыми пользователь вошел в систему. Эта новая учетная запись хранится как часть вашего проекта Firebase и может использоваться для идентификации пользователя во всех приложениях вашего проекта, независимо от того, как пользователь входит в систему. В ваших приложениях вы можете получить основную информацию о профиле пользователя из объекта firebase::auth::User
. См. Управление пользователями .
В правилах безопасности Firebase Realtime Database и Cloud Storage вы можете получить уникальный идентификатор вошедшего пользователя из переменной auth и использовать его для управления тем, к каким данным пользователь может получить доступ.