Accesso degli utenti con Apple su iOS
Questo documento mostra come utilizzare Identity Platform per aggiungere Accedi con Apple alla tua app per iOS.
Prima di iniziare
Crea un'app per iOS che utilizzi Identity Platform.
Partecipa al programma per sviluppatori Apple.
Configurare l'app con Apple
Sul sito Apple Developer:
Attivare la funzionalità Accedi con Apple per la tua app.
Se utilizzi Identity Platform per inviare email ai tuoi utenti, configura il tuo progetto con il servizio di inoltro email privato di Apple utilizzando l'indirizzo email che segue:
noreply@project-id.firebaseapp.com
Puoi anche utilizzare un modello email personalizzato, se la tua app ne ha uno.
Conformità ai requisiti di Apple relativi ai dati anonimizzati
Apple offre agli utenti la possibilità di anonimizzare i propri dati, incluso il loro indirizzo email. Apple assegna agli utenti che selezionano questa opzione un'immagine offuscata
indirizzo email con il dominio privaterelay.appleid.com
.
La tua app deve rispettare eventuali norme o termini per gli sviluppatori di Apple relativi agli ID Apple anonimizzati. Ciò include l'ottenimento del consenso degli utenti prima associazione di informazioni che consentono l'identificazione personale (PII) a un indirizzo ID Apple. Le azioni che coinvolgono le PII includono, a titolo esemplificativo:
- Collegare un indirizzo email a un ID Apple anonimo o viceversa.
- Collegare un numero di telefono a un ID Apple anonimo o viceversa
- Collegamento di una credenziale social non anonima, come Facebook o Google, a un ID Apple anonimizzato o viceversa.
Per ulteriori informazioni, consulta il Contratto di licenza del programma per sviluppatori Apple per il tuo account sviluppatore Apple.
Configurare Apple come provider
Per configurare Apple come provider di identità:
Vai alla pagina Provider di identità nella console Google Cloud.
Fai clic su Add A Provider (Aggiungi un provider).
Seleziona Mela dall'elenco.
In Piattaforma, seleziona iOS.
Inserisci l'ID pacchetto dell'app.
Registra i domini della tua app facendo clic su Aggiungi dominio in Domini autorizzati. Ai fini dello sviluppo,
localhost
è già sono abilitate per impostazione predefinita.In Configura la tua applicazione, fai clic su iOS. Copia il nel codice dell'app per inizializzare Identity Platform SDK client.
Fai clic su Salva.
Accesso degli utenti con l'SDK client
Esegui l'accesso dell'utente e ottieni un token ID con il Framework dei servizi di autenticazione.
Genera una stringa casuale, nota come nonce, richiamando
SecRandomCopyBytes(_:_:_:)
Il nonce viene utilizzato per impedire attacchi di replay. Includi l'hash SHA-256 il tuo nonce nella richiesta di autenticazione e Apple lo restituisce, non modificato, nella risposta. Identity Platform convalida quindi la risposta confrontando l'hash originale con il valore restituito da Apple.
Avvia il flusso di accesso di Apple, incluso l'hash SHA-256 del nonce che utilizzi creata nel passaggio precedente e una classe delegato per gestire risposta:
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() } @available(iOS 13, *) private func sha256(_ input: String) -> String { let inputData = Data(input.utf8) let hashedData = SHA256.hash(data: inputData) let hashString = hashedData.compactMap { return String(format: "%02x", $0) }.joined() return hashString }
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]; } - (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; }
Gestisci la risposta di Apple nell'implementazione di
ASAuthorizationControllerDelegate
. Se l'accesso va a buon fine, utilizza il token ID proveniente dalla risposta di Apple con il nonce non sottoposto ad hashing per autenticarti con Identity Platform: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. let credential = OAuthProvider.credential(withProviderID: "apple.com", IDToken: idTokenString, rawNonce: nonce) // 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. FIROAuthCredential *credential = [FIROAuthProvider credentialWithProviderID:@"apple.com" IDToken:idToken rawNonce:rawNonce]; // 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); }
A differenza di molti altri provider di identità, Apple non fornisce l'URL delle foto.
Se un utente sceglie di non condividere il proprio indirizzo email reale con l'app, Apple esegue il provisioning
un indirizzo email univoco che l'utente possa condividere. L'email assume il formato
xyz@privaterelay.appleid.com
. Se hai configurato l'inoltro di email private
servizio, Apple inoltra le email inviate all'indirizzo anonimo all'indirizzo
.
Apple condivide solo le informazioni utente, ad esempio i nomi visualizzati, con le app
la prima volta che un utente esegue l'accesso. Nella maggior parte dei casi, Identity Platform memorizza questi
dati, che puoi recuperare utilizzando firebase.auth().currentUser.displayName
durante le sessioni future. Tuttavia, se hai consentito agli utenti di accedere alla tua app
utilizzando Apple prima dell'integrazione con Identity Platform, le informazioni degli utenti
non è disponibile.
Eliminazione dell'account utente
Apple richiede app per iOS che supportano la creazione di account Deve inoltre consentire agli utenti di avviare l'eliminazione del proprio account dall'app.
Quando elimini un account utente, devi revocare il token dell'utente prima di eliminare l'account, nonché tutti i dati che hai archiviato per l'utente in Firestore, Cloud Storage e nel database Firebase Realtime. Per ulteriori informazioni, vedi Offrire l'eliminazione dell'account nell'app nella documentazione di supporto per gli sviluppatori di Apple.
Poiché Identity Platform non archivia i token utente quando gli utenti vengono creati con Accedi con Apple, devi chiedere all'utente di eseguire l'accesso prima di revocare ed eliminare l'account. In alternativa, per evitare di chiedere all'utente di accedere di nuovo Se un utente ha eseguito l'accesso con Accedi con Apple, puoi memorizzare l'autorizzazione da riutilizzare durante la revoca del token.
Per revocare il token di un utente ed eliminare il suo account, esegui quanto segue:
Swift
let user = Auth.auth().currentUser
// Check if the user has a token.
if let providerData = user?.providerData {
for provider in providerData {
guard let provider = provider as? FIRUserInfo else {
continue
}
if provider.providerID() == "apple.com" {
isAppleProviderLinked = true
}
}
}
// Re-authenticate the user and revoke their token
if isAppleProviderLinked {
let request = appleIDRequest(withState: "revokeAppleTokenAndDeleteUser")
let controller = ASAuthorizationController(authorizationRequests: [request])
controller.delegate = self
controller.presentationContextProvider = self
controller.performRequests()
} else {
// Usual user deletion
}
func authorizationController(
controller: ASAuthorizationController,
didCompleteWithAuthorization authorization: ASAuthorization
) {
if authorization.credential is ASAuthorizationAppleIDCredential {
let appleIDCredential = authorization.credential as? ASAuthorizationAppleIDCredential
if authorization.credential is ASAuthorizationAppleIDCredential {
if appleIDCredential.state == "signIn" {
// Sign in with Firebase.
// ...
} else if appleIDCredential.state == "revokeAppleTokenAndDeleteUser" {
// Revoke token with Firebase.
Auth.auth().revokeTokenWithAuthorizationCode(code) { error in
if error != nil {
// Token revocation failed.
} else {
// Token revocation succeeded then delete user again.
let user = Auth.auth().currentUser
user?.delete { error in
// ...
}
}
}
}
}
}
}
Objective-C
FIRUser *user = [FIRAuth auth].currentUser;
// Check if the user has a token.
BOOL isAppleProviderLinked = false;
for (id<FIRUserInfo> provider in user.providerData) {
if ([[provider providerID] isEqual:@"apple.com"]) {
isAppleProviderLinked = true;
}
}
// Re-authenticate the user and revoke their token
if (isAppleProviderLinked) {
if (@available(iOS 13, *)) {
ASAuthorizationAppleIDRequest *request =
[self appleIDRequestWithState:@"revokeAppleTokenAndDeleteUser"];
ASAuthorizationController *controller = [[ASAuthorizationController alloc]
initWithAuthorizationRequests:@[ request ]];
controller.delegate = self;
controller.presentationContextProvider = self;
[controller performRequests];
}
} else {
// Usual user deletion
}
- (void)authorizationController:(ASAuthorizationController *)controller
didCompleteWithAuthorization:(ASAuthorization *)authorization
API_AVAILABLE(ios(13.0)) {
if ([authorization.credential
isKindOfClass:[ASAuthorizationAppleIDCredential class]]) {
ASAuthorizationAppleIDCredential *appleIDCredential =
authorization.credential;
if ([appleIDCredential.state isEqualToString:@"signIn"]) {
// Sign in with Firebase.
// ...
} else if ([appleIDCredential.state
isEqualToString:@"revokeAppleTokenAndDeleteUser"]) {
// Revoke token with Firebase.
NSString *code =
[[NSString alloc] initWithData:appleIDCredential.authorizationCode
encoding:NSUTF8StringEncoding];
[[FIRAuth auth]
revokeTokenWithAuthorizationCode:code
completion:^(NSError *_Nullable error) {
if (error != nil) {
// Token revocation failed.
} else {
// Token revocation succeeded then delete
// user again.
FIRUser *user = [FIRAuth auth].currentUser;
[user deleteWithCompletion:^(
NSError *_Nullable error){
// ...
}];
}
}];
}
}
}
Passaggi successivi
- Scopri di più sugli utenti di Identity Platform.
- Consentire l'accesso degli utenti ad altri provider di identità.