Uçtan uca OAuth 2.0 oturum açma akışını gerçekleştirmek için Firebase SDK'sını kullanarak kullanıcılarınızın Apple Kimliklerini kullanarak Firebase'de kimlik doğrulaması yapmasına izin verebilirsiniz.
Başlamadan önce
Kullanıcıların Apple ile oturum açmasını sağlamak için önce Apple'ın geliştirici sitesinde Apple ile Oturum Açma'yı yapılandırın, ardından Firebase projeniz için oturum açma sağlayıcı olarak Apple'ı etkinleştirin.
Apple Geliştirici Programı'na katılma
Apple ile oturum açma özelliği yalnızca Apple Developer Program üyeleri tarafından yapılandırılabilir.
Apple ile oturum açma özelliğini yapılandırma
- Apple'ın geliştirici sitesindeki Certificates, Identifiers & Profiles (Sertifikalar, Tanımlayıcılar ve Profiller) sayfasında uygulamanız için Apple ile oturum açma özelliğini etkinleştirin.
- Web için Apple ile oturum açma özelliğini yapılandırma başlıklı makalenin ilk bölümünde açıklandığı şekilde web sitenizi uygulamanızla ilişkilendirin. İstendiğinde aşağıdaki URL'yi Dönüş URL'si olarak kaydedin:
Firebase proje kimliğinizi Firebase konsol ayarları sayfasından alabilirsiniz. İşlemi tamamladığınızda yeni hizmet kimliğinizi not edin. Bu kimliğe bir sonraki bölümde ihtiyacınız olacak.https://YOUR_FIREBASE_PROJECT_ID.firebaseapp.com/__/auth/handler
- Apple ile oturum açma özel anahtarı oluşturun. Bir sonraki bölümde yeni özel anahtarınıza ve anahtar kimliğinize ihtiyacınız olacak.
- Firebase Authentication'nın, kullanıcılara e-posta gönderen özelliklerinden herhangi birini kullanıyorsanız (ör. e-posta bağlantısıyla oturum açma, e-posta adresi doğrulama, hesap değişikliği iptali vb.) Apple'ın özel e-posta aktarma hizmetini yapılandırın ve
noreply@YOUR_FIREBASE_PROJECT_ID.firebaseapp.com
(veya özelleştirilmiş e-posta şablonu alanınız) için kayıt yapın. Böylece Apple, Firebase Authentication tarafından gönderilen e-postaları anonimleştirilmiş Apple e-posta adreslerine aktarabilir.
Apple'ı oturum açma sağlayıcısı olarak etkinleştirme
- Firebase'i Apple projenize ekleyin. Uygulamanızı Firebase konsolunda oluştururken uygulamanızın paket kimliğini kaydettiğinizden emin olun.
- Firebase konsolunda Auth (Kimlik Doğrulama) bölümünü açın. Oturum açma yöntemi sekmesinde Apple sağlayıcısını etkinleştirin. Önceki bölümde oluşturduğunuz hizmet kimliğini belirtin. Ayrıca, OAuth kod akışı yapılandırması bölümünde Apple Ekip Kimliğinizi ve önceki bölümde oluşturduğunuz özel anahtarı ve anahtar kimliğini belirtin.
Apple'ın anonimleştirilmiş veri şartlarına uyun
Apple ile Giriş, kullanıcılara oturum açarken e-posta adresleri de dahil olmak üzere verilerini anonimleştirme seçeneği sunar. Bu seçeneği belirleyen kullanıcıların privaterelay.appleid.com
alan adıyla e-posta adresleri olur. Uygulamanızda Apple ile Giriş'i kullandığınızda, bu anonimleştirilmiş Apple kimlikleriyle ilgili olarak Apple'ın geçerli tüm geliştirici politikalarına veya şartlarına uymanız gerekir.
Bu, kimliği doğrudan tanımlayan kişisel bilgileri anonimleştirilmiş bir Apple Kimliği ile ilişkilendirmeden önce gerekli kullanıcı iznini almayı içerir. Firebase Authentication kullanılırken aşağıdaki işlemler yapılabilir:
- Anonimleştirilmiş bir Apple Kimliği'ne e-posta adresi bağlayabilir veya tam tersini yapabilirsiniz.
- Anonimleştirilmiş bir Apple Kimliği'ne telefon numarası bağlama veya tam tersi
- Anonim olmayan bir sosyal kimlik bilgisini (Facebook, Google vb.) anonimleştirilmiş bir Apple Kimliği'ne veya tam tersi şekilde bağlamak
Yukarıdaki listede olası her duruma yer verilmemiştir. Uygulamanızın Apple'ın şartlarını karşıladığından emin olmak için geliştirici hesabınızın Üyelik bölümündeki Apple Geliştirici Programı Lisans Sözleşmesi'ne bakın.
Apple ile oturum açma ve Firebase ile kimlik doğrulama
Apple hesabı ile kimlik doğrulamak için önce kullanıcıyı Apple'ın AuthenticationServices
çerçevesini kullanarak Apple hesabında oturum açtırın, ardından Apple'ın yanıtındaki kimlik jetonunu kullanarak bir Firebase AuthCredential
nesnesi oluşturun:
Her oturum açma isteği için rastgele bir dize ("nonce") oluşturun. Bu dizeyi, aldığınız kimlik jetonunun özellikle uygulamanızın kimlik doğrulama isteğine yanıt olarak verildiğinden emin olmak için kullanırsınız. Bu adım, yeniden oynatma saldırılarını önlemek için önemlidir.
Aşağıdaki örnekte olduğu gibi,
SecRandomCopyBytes(_:_:_)
ile kriptografik olarak güvenli bir nonce oluşturabilirsiniz:Swift
private func randomNonceString(length: Int = 32) -> String { precondition(length > 0) var randomBytes = [UInt8](repeating: 0, count: length) let errorCode = SecRandomCopyBytes(kSecRandomDefault, randomBytes.count, &randomBytes) if errorCode != errSecSuccess { fatalError( "Unable to generate nonce. SecRandomCopyBytes failed with OSStatus \(errorCode)" ) } let charset: [Character] = Array("0123456789ABCDEFGHIJKLMNOPQRSTUVXYZabcdefghijklmnopqrstuvwxyz-._") let nonce = randomBytes.map { byte in // Pick a random character from the set, wrapping around if needed. charset[Int(byte) % charset.count] } return String(nonce) }
Objective-C
// Adapted from https://auth0.com/docs/api-auth/tutorials/nonce#generate-a-cryptographically-random-nonce - (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--; } } } return [result copy]; }
Oturum açma isteğinizle birlikte nonce'ın SHA256 hash değerini gönderirsiniz. Bu değer, Apple tarafından yanıtta değiştirilmeden iletilir. Firebase, orijinal nonce'ı karma oluşturma işlevinden geçirerek ve Apple tarafından iletilen değerle karşılaştırarak yanıtı doğrular.
Swift
@available(iOS 13, *) private func sha256(_ input: String) -> String { let inputData = Data(input.utf8) let hashedData = SHA256.hash(data: inputData) let hashString = hashedData.compactMap { String(format: "%02x", $0) }.joined() return hashString }
Objective-C
- (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; }
İsteğinize, Apple'ın yanıtını işleyecek olan nonce'ın ve temsilci sınıfının SHA256 karmasını da ekleyerek Apple'ın oturum açma akışını başlatın (sonraki adıma bakın):
Swift
import CryptoKit // Unhashed nonce. fileprivate var currentNonce: String? @available(iOS 13, *) func startSignInWithAppleFlow() { let nonce = randomNonceString() currentNonce = nonce let appleIDProvider = ASAuthorizationAppleIDProvider() let request = appleIDProvider.createRequest() request.requestedScopes = [.fullName, .email] request.nonce = sha256(nonce) let authorizationController = ASAuthorizationController(authorizationRequests: [request]) authorizationController.delegate = self authorizationController.presentationContextProvider = self authorizationController.performRequests() }
Objective-C
@import CommonCrypto; - (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]; }
Apple'ın yanıtını
ASAuthorizationControllerDelegate
uygulamanızda ele alın. Oturum açma işlemi başarılı olduysa Firebase'de kimlik doğrulaması yapmak için Apple'ın yanıtındaki ID token'ı, karma oluşturulmamış nonce ile birlikte kullanın:Swift
@available(iOS 13.0, *) extension MainViewController: ASAuthorizationControllerDelegate { func authorizationController(controller: ASAuthorizationController, didCompleteWithAuthorization authorization: ASAuthorization) { if let appleIDCredential = authorization.credential as? ASAuthorizationAppleIDCredential { guard let nonce = currentNonce else { fatalError("Invalid state: A login callback was received, but no login request was sent.") } guard let appleIDToken = appleIDCredential.identityToken else { print("Unable to fetch identity token") return } guard let idTokenString = String(data: appleIDToken, encoding: .utf8) else { print("Unable to serialize token string from data: \(appleIDToken.debugDescription)") return } // Initialize a Firebase credential, including the user's full name. let credential = OAuthProvider.appleCredential(withIDToken: idTokenString, rawNonce: nonce, fullName: appleIDCredential.fullName) // Sign in with Firebase. Auth.auth().signIn(with: credential) { (authResult, error) in if error { // Error. If error.code == .MissingOrInvalidNonce, make sure // you're sending the SHA256-hashed nonce as a hex string with // your request to Apple. print(error.localizedDescription) return } // User is signed in to Firebase with Apple. // ... } } } func authorizationController(controller: ASAuthorizationController, didCompleteWithError error: Error) { // Handle error. print("Sign in with Apple errored: \(error)") } }
Objective-C
- (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); } // Initialize a Firebase credential, including the user's full name. FIROAuthCredential *credential = [FIROAuthProvider appleCredentialWithIDToken:IDToken rawNonce:self.appleRawNonce fullName:appleIDCredential.fullName]; // Sign in with Firebase. [[FIRAuth auth] signInWithCredential:credential completion:^(FIRAuthDataResult * _Nullable authResult, NSError * _Nullable error) { if (error != nil) { // Error. If error.code == FIRAuthErrorCodeMissingOrInvalidNonce, // make sure you're sending the SHA256-hashed nonce as a hex string // with your request to Apple. return; } // Sign-in succeeded! }]; } } - (void)authorizationController:(ASAuthorizationController *)controller didCompleteWithError:(NSError *)error API_AVAILABLE(ios(13.0)) { NSLog(@"Sign in with Apple errored: %@", error); }
Firebase Auth tarafından desteklenen diğer sağlayıcıların aksine Apple, fotoğraf URL'si sağlamaz.
Ayrıca, kullanıcı e-postasını uygulamayla paylaşmamayı seçtiğinde Apple, bu kullanıcı için benzersiz bir e-posta adresi (xyz@privaterelay.appleid.com
biçiminde) sağlar ve bu adresi uygulamanızla paylaşır. Özel e-posta geçiş hizmetini yapılandırdıysanız Apple, anonimleştirilmiş adrese gönderilen e-postaları kullanıcının gerçek e-posta adresine yönlendirir.
Yeniden kimlik doğrulama ve hesap bağlama
Aynı kalıp, oturum açma işleminin yakın zamanda yapılması gereken hassas işlemler için yeni bir kimlik bilgisi almak üzere kullanabileceğiniz reauthenticateWithCredential()
ile de kullanılabilir:
Swift
// Initialize a fresh Apple credential with Firebase.
let credential = OAuthProvider.credential(
withProviderID: "apple.com",
IDToken: appleIdToken,
rawNonce: rawNonce
)
// Reauthenticate current Apple user with fresh Apple credential.
Auth.auth().currentUser.reauthenticate(with: credential) { (authResult, error) in
guard error != nil else { return }
// Apple user successfully re-authenticated.
// ...
}
Objective-C
FIRAuthCredential *credential = [FIROAuthProvider credentialWithProviderID:@"apple.com",
IDToken:appleIdToken,
rawNonce:rawNonce];
[[FIRAuth auth].currentUser
reauthenticateWithCredential:credential
completion:^(FIRAuthDataResult * _Nullable authResult,
NSError * _Nullable error) {
if (error) {
// Handle error.
}
// Apple user successfully re-authenticated.
// ...
}];
Ayrıca, farklı kimlik sağlayıcıları mevcut hesaplara bağlamak için linkWithCredential()
kullanabilirsiniz.
Apple'ın, kullanıcıların Apple hesaplarını diğer verilere bağlamadan önce kullanıcılardan açık rıza almanızı zorunlu kıldığını unutmayın.
Apple ile oturum açma, kimlik doğrulama kimlik bilgilerini mevcut bir hesaba bağlamak için yeniden kullanmanıza izin vermez. Apple ile oturum açma kimlik bilgisini başka bir hesaba bağlamak istiyorsanız önce eski Apple ile oturum açma kimlik bilgisini kullanarak hesapları bağlamayı denemeli, ardından döndürülen hatayı inceleyerek yeni bir kimlik bilgisi bulmalısınız.
Yeni kimlik bilgisi, hatanın userInfo
sözlüğünde yer alır ve AuthErrorUserInfoUpdatedCredentialKey
anahtarı aracılığıyla erişilebilir.
Örneğin, bir Facebook hesabını mevcut Firebase hesabına bağlamak için kullanıcıyı Facebook'ta oturum açtığında aldığınız erişim jetonunu kullanın:
Swift
// Initialize a Facebook credential with Firebase.
let credential = FacebookAuthProvider.credential(
withAccessToken: AccessToken.current!.tokenString
)
// Assuming the current user is an Apple user linking a Facebook provider.
Auth.auth().currentUser.link(with: credential) { (authResult, error) in
// Facebook credential is linked to the current Apple user.
// The user can now sign in with Facebook or Apple to the same Firebase
// account.
// ...
}
Objective-C
// Initialize a Facebook credential with Firebase.
FacebookAuthCredential *credential = [FIRFacebookAuthProvider credentialWithAccessToken:accessToken];
// Assuming the current user is an Apple user linking a Facebook provider.
[FIRAuth.auth linkWithCredential:credential completion:^(FIRAuthDataResult * _Nullable authResult, NSError * _Nullable error) {
// Facebook credential is linked to the current Apple user.
// The user can now sign in with Facebook or Apple to the same Firebase
// account.
// ...
}];
Jeton iptali
Apple, hesap oluşturmayı destekleyen uygulamaların, App Store İnceleme Kuralları'nda belirtildiği gibi kullanıcıların hesaplarını uygulama içinden silmelerine olanak tanımasını zorunlu kılar.
Bu koşulu karşılamak için aşağıdaki adımları uygulayın:
Firebase, kullanıcılar Apple ile Giriş Yap kullanılarak oluşturulduğunda kullanıcı jetonlarını saklamadığından, jetonlarını iptal edip hesabı silmeden önce kullanıcının tekrar oturum açmasını istemeniz gerekir.
Swift
private func deleteCurrentUser() { do { let nonce = try CryptoUtils.randomNonceString() currentNonce = nonce let appleIDProvider = ASAuthorizationAppleIDProvider() let request = appleIDProvider.createRequest() request.requestedScopes = [.fullName, .email] request.nonce = CryptoUtils.sha256(nonce) let authorizationController = ASAuthorizationController(authorizationRequests: [request]) authorizationController.delegate = self authorizationController.presentationContextProvider = self authorizationController.performRequests() } catch { // In the unlikely case that nonce generation fails, show error view. displayError(error) } }
Yetkilendirme kodunu
ASAuthorizationAppleIDCredential
adresinden alın ve kullanıcı jetonlarını iptal etmek içinAuth.auth().revokeToken(withAuthorizationCode:)
işlevini çağırmak üzere kullanın.Swift
func authorizationController(controller: ASAuthorizationController, didCompleteWithAuthorization authorization: ASAuthorization) { guard let appleIDCredential = authorization.credential as? ASAuthorizationAppleIDCredential else { print("Unable to retrieve AppleIDCredential") return } guard let _ = currentNonce else { fatalError("Invalid state: A login callback was received, but no login request was sent.") } guard let appleAuthCode = appleIDCredential.authorizationCode else { print("Unable to fetch authorization code") return } guard let authCodeString = String(data: appleAuthCode, encoding: .utf8) else { print("Unable to serialize auth code string from data: \(appleAuthCode.debugDescription)") return } Task { do { try await Auth.auth().revokeToken(withAuthorizationCode: authCodeString) try await user?.delete() self.updateUI() } catch { self.displayError(error) } } }
Son olarak, kullanıcı hesabını (ve ilişkili tüm verileri) silin.
Sonraki adımlar
Bir kullanıcı ilk kez oturum açtıktan sonra yeni bir kullanıcı hesabı oluşturulur ve kullanıcının oturum açtığı kimlik bilgilerine (kullanıcı adı ve şifre, telefon numarası veya kimlik doğrulama sağlayıcı bilgileri) bağlanır. Bu yeni hesap, Firebase projenizin bir parçası olarak depolanır ve kullanıcının oturum açma şeklinden bağımsız olarak projenizdeki her uygulamada kullanıcıyı tanımlamak için kullanılabilir.
-
Uygulamalarınızda, kullanıcının temel profil bilgilerini
User
nesnesinden alabilirsiniz. Kullanıcıları yönetme başlıklı makaleyi inceleyin. Firebase Realtime Database ve Cloud Storage Güvenlik Kurallarınızda, oturum açmış kullanıcının benzersiz kullanıcı kimliğini
auth
değişkeninden alabilir ve kullanıcının hangi verilere erişebileceğini kontrol etmek için bu kimliği kullanabilirsiniz.
Kimlik doğrulama sağlayıcı kimlik bilgilerini mevcut bir kullanıcı hesabına bağlayarak kullanıcıların uygulamanızda birden fazla kimlik doğrulama sağlayıcı kullanarak oturum açmasına izin verebilirsiniz.
Bir kullanıcının oturumunu kapatmak için
signOut:
işlevini çağırın.
Swift
let firebaseAuth = Auth.auth() do { try firebaseAuth.signOut() } catch let signOutError as NSError { print("Error signing out: %@", signOutError) }
Objective-C
NSError *signOutError; BOOL status = [[FIRAuth auth] signOut:&signOutError]; if (!status) { NSLog(@"Error signing out: %@", signOutError); return; }
Ayrıca, kimlik doğrulama hatalarının tamamı için hata işleme kodu eklemek de isteyebilirsiniz. Hataları İşleme bölümüne bakın.