Inicio de sesión de usuarios con Facebook en iOS
Puedes permitir que tus usuarios se autentiquen con Identity Platform usando sus cuentas de Facebook integrando Inicio de sesión con Facebook o Inicio de sesión limitado con Facebook en tu aplicación. En esta página se explica cómo usar Identity Platform para añadir la opción de iniciar sesión con Facebook a tu aplicación iOS.
Antes de empezar
Incluye los siguientes pods en tu
Podfile
:pod 'FirebaseAuth'
Ve a la página Proveedores de identidades de la consola de Google Cloud .
Haz clic en Add A Provider (Añadir proveedor).
Selecciona Facebook en la lista.
Introduce tu ID de aplicación y tu secreto de aplicación de Facebook. Si aún no tienes un ID y un secreto, puedes obtenerlos en la página Facebook for Developers.
Configura el URI que aparece en Configurar Facebook como un URI de redirección de OAuth válido para tu aplicación de Facebook. Si has configurado un dominio personalizado en Identity Platform, actualiza el URI de redirección en la configuración de tu aplicación de Facebook para que use el dominio personalizado en lugar del dominio predeterminado. Por ejemplo, cambia
https://myproject.firebaseapp.com/__/auth/handler
porhttps://auth.myownpersonaldomain.com/__/auth/handler
.Para registrar los dominios de tu aplicación, haz clic en Añadir dominio en Dominios autorizados. Para las actividades de desarrollo,
localhost
ya está habilitado de forma predeterminada.En Configura tu aplicación, haz clic en Detalles de la configuración. Copia el fragmento en el código de tu aplicación para inicializar el SDK de cliente de Identity Platform.
Haz clic en Guardar.
Implementar el inicio de sesión con Facebook
Para usar el inicio de sesión de Facebook clásico, sigue estos pasos. También puedes usar el inicio de sesión limitado de Facebook, como se muestra en la siguiente sección.
- Integra Inicio de sesión con Facebook en tu aplicación siguiendo la
documentación para desarrolladores. Cuando inicialices el objeto
FBSDKLoginButton
, asigna un delegado para recibir eventos de inicio y cierre de sesión. Por ejemplo:Swift
let loginButton = FBSDKLoginButton() loginButton.delegate = self
Objective‑C
FBSDKLoginButton *loginButton = [[FBSDKLoginButton alloc] init]; loginButton.delegate = self;
didCompleteWithResult:error:
.Swift
func loginButton(_ loginButton: FBSDKLoginButton!, didCompleteWith result: FBSDKLoginManagerLoginResult!, error: Error!) { if let error = error { print(error.localizedDescription) return } // ... }
Objective‑C
- (void)loginButton:(FBSDKLoginButton *)loginButton didCompleteWithResult:(FBSDKLoginManagerLoginResult *)result error:(NSError *)error { if (error == nil) { // ... } else { NSLog(error.localizedDescription); } }
- Importa el módulo de Firebase a tu
UIApplicationDelegate
:Swift
import FirebaseCore import FirebaseAuth
Objective‑C
@import FirebaseCore; @import FirebaseAuth;
- Configura una instancia compartida de
FirebaseApp
; normalmente, en el métodoapplication:didFinishLaunchingWithOptions:
de tu aplicación:Swift
// Use Firebase library to configure APIs FirebaseApp.configure()
Objective‑C
// Use Firebase library to configure APIs [FIRApp configure];
- Una vez que un usuario haya iniciado sesión correctamente, en tu implementación de
didCompleteWithResult:error:
, obtén un token de acceso para el usuario que haya iniciado sesión e intercámbialo por una credencial de Identity Platform:Swift
let credential = FacebookAuthProvider .credential(withAccessToken: AccessToken.current!.tokenString)
Objective‑C
FIRAuthCredential *credential = [FIRFacebookAuthProvider credentialWithAccessToken:[FBSDKAccessToken currentAccessToken].tokenString];
Implementar el inicio de sesión limitado de Facebook
Para usar el inicio de sesión limitado de Facebook en lugar del inicio de sesión de Facebook "clásico", sigue estos pasos.
- Integra el inicio de sesión limitado de Facebook en tu aplicación siguiendo la documentación para desarrolladores.
- Por cada solicitud de inicio de sesión, genera una cadena aleatoria única (un "nonce") que usarás para asegurarte de que el token de ID que obtengas se haya concedido específicamente en respuesta a la solicitud de autenticación de tu aplicación. Este paso es importante para
evitar ataques de repetición.
Puedes generar un nonce criptográficamente seguro en iOS con
SecRandomCopyBytes(_:_:_)
, como en el siguiente ejemplo: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]; }
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; }
- Cuando configures el
FBSDKLoginButton
, asigna un delegado para recibir eventos de inicio y cierre de sesión, define el modo de seguimiento comoFBSDKLoginTrackingLimited
y adjunta un nonce. Por ejemplo:Swift
func setupLoginButton() { let nonce = randomNonceString() currentNonce = nonce loginButton.delegate = self loginButton.loginTracking = .limited loginButton.nonce = sha256(nonce) }
Objective‑C
- (void)setupLoginButton { NSString *nonce = [self randomNonce:32]; self.currentNonce = nonce; self.loginButton.delegate = self; self.loginButton.loginTracking = FBSDKLoginTrackingLimited self.loginButton.nonce = [self stringBySha256HashingString:nonce]; }
didCompleteWithResult:error:
.Swift
func loginButton(_ loginButton: FBSDKLoginButton!, didCompleteWith result: FBSDKLoginManagerLoginResult!, error: Error!) { if let error = error { print(error.localizedDescription) return } // ... }
Objective‑C
- (void)loginButton:(FBSDKLoginButton *)loginButton didCompleteWithResult:(FBSDKLoginManagerLoginResult *)result error:(NSError *)error { if (error == nil) { // ... } else { NSLog(error.localizedDescription); } }
- Importa el módulo de Firebase a tu
UIApplicationDelegate
:Swift
import Firebase
Objective‑C
@import Firebase;
- Configura una instancia compartida de
FirebaseApp
; normalmente, en el métodoapplication:didFinishLaunchingWithOptions:
de tu aplicación:Swift
// Use Firebase library to configure APIs FirebaseApp.configure()
Objective‑C
// Use Firebase library to configure APIs [FIRApp configure];
- Cuando un usuario inicie sesión correctamente en tu implementación de
didCompleteWithResult:error:
, usa el token de ID de la respuesta de Facebook con el nonce sin cifrar para obtener una credencial de Identity Platform:Swift
// Initialize an Identity Platform credential. let idTokenString = AuthenticationToken.current?.tokenString let nonce = currentNonce let credential = OAuthProvider.credential(withProviderID: "facebook.com", IDToken: idTokenString, rawNonce: nonce)
Objective‑C
// Initialize an Identity Platform credential. NSString *idTokenString = FBSDKAuthenticationToken.currentAuthenticationToken.tokenString; NSString *rawNonce = self.currentNonce; FIROAuthCredential *credential = [FIROAuthProvider credentialWithProviderID:@"facebook.com" IDToken:idTokenString rawNonce:rawNonce];
Autenticar con Identity Platform
Por último, autentica con Identity Platform mediante la credencial de Identity Platform:
Swift
Auth.auth().signIn(with: credential) { authResult, error in if let error = error { let authError = error as NSError if isMFAEnabled, authError.code == AuthErrorCode.secondFactorRequired.rawValue { // The user is a multi-factor user. Second factor challenge is required. let resolver = authError .userInfo[AuthErrorUserInfoMultiFactorResolverKey] as! MultiFactorResolver var displayNameString = "" for tmpFactorInfo in resolver.hints { displayNameString += tmpFactorInfo.displayName ?? "" displayNameString += " " } self.showTextInputPrompt( withMessage: "Select factor to sign in\n\(displayNameString)", completionBlock: { userPressedOK, displayName in var selectedHint: PhoneMultiFactorInfo? for tmpFactorInfo in resolver.hints { if displayName == tmpFactorInfo.displayName { selectedHint = tmpFactorInfo as? PhoneMultiFactorInfo } } PhoneAuthProvider.provider() .verifyPhoneNumber(with: selectedHint!, uiDelegate: nil, multiFactorSession: resolver .session) { verificationID, error in if error != nil { print( "Multi factor start sign in failed. Error: \(error.debugDescription)" ) } else { self.showTextInputPrompt( withMessage: "Verification code for \(selectedHint?.displayName ?? "")", completionBlock: { userPressedOK, verificationCode in let credential: PhoneAuthCredential? = PhoneAuthProvider.provider() .credential(withVerificationID: verificationID!, verificationCode: verificationCode!) let assertion: MultiFactorAssertion? = PhoneMultiFactorGenerator .assertion(with: credential!) resolver.resolveSignIn(with: assertion!) { authResult, error in if error != nil { print( "Multi factor finanlize sign in failed. Error: \(error.debugDescription)" ) } else { self.navigationController?.popViewController(animated: true) } } } ) } } } ) } else { self.showMessagePrompt(error.localizedDescription) return } // ... return } // User is signed in // ... }
Objective‑C
[[FIRAuth auth] signInWithCredential:credential completion:^(FIRAuthDataResult * _Nullable authResult, NSError * _Nullable error) { if (isMFAEnabled && error && error.code == FIRAuthErrorCodeSecondFactorRequired) { FIRMultiFactorResolver *resolver = error.userInfo[FIRAuthErrorUserInfoMultiFactorResolverKey]; NSMutableString *displayNameString = [NSMutableString string]; for (FIRMultiFactorInfo *tmpFactorInfo in resolver.hints) { [displayNameString appendString:tmpFactorInfo.displayName]; [displayNameString appendString:@" "]; } [self showTextInputPromptWithMessage:[NSString stringWithFormat:@"Select factor to sign in\n%@", displayNameString] completionBlock:^(BOOL userPressedOK, NSString *_Nullable displayName) { FIRPhoneMultiFactorInfo* selectedHint; for (FIRMultiFactorInfo *tmpFactorInfo in resolver.hints) { if ([displayName isEqualToString:tmpFactorInfo.displayName]) { selectedHint = (FIRPhoneMultiFactorInfo *)tmpFactorInfo; } } [FIRPhoneAuthProvider.provider verifyPhoneNumberWithMultiFactorInfo:selectedHint UIDelegate:nil multiFactorSession:resolver.session completion:^(NSString * _Nullable verificationID, NSError * _Nullable error) { if (error) { [self showMessagePrompt:error.localizedDescription]; } else { [self showTextInputPromptWithMessage:[NSString stringWithFormat:@"Verification code for %@", selectedHint.displayName] completionBlock:^(BOOL userPressedOK, NSString *_Nullable verificationCode) { FIRPhoneAuthCredential *credential = [[FIRPhoneAuthProvider provider] credentialWithVerificationID:verificationID verificationCode:verificationCode]; FIRMultiFactorAssertion *assertion = [FIRPhoneMultiFactorGenerator assertionWithCredential:credential]; [resolver resolveSignInWithAssertion:assertion completion:^(FIRAuthDataResult * _Nullable authResult, NSError * _Nullable error) { if (error) { [self showMessagePrompt:error.localizedDescription]; } else { NSLog(@"Multi factor finanlize sign in succeeded."); } }]; }]; } }]; }]; } else if (error) { // ... return; } // User successfully signed in. Get user data from the FIRUser object if (authResult == nil) { return; } FIRUser *user = authResult.user; // ... }];
Siguientes pasos
- Más información sobre los usuarios de Identity Platform
- Permite que los usuarios inicien sesión con otros proveedores de identidades.