Autenticar usando Apple e C++

Você pode permitir que seus usuários se autentiquem com o Firebase usando o ID Apple usando o SDK do Firebase para realizar o fluxo de login do OAuth 2.0 de ponta a ponta.

Antes de você começar

Para fazer login de usuários que usam a Apple, primeiro configure Sign In with Apple no site do desenvolvedor da Apple e, em seguida, ative a Apple como provedor de login para seu projeto do Firebase.

Participe do Programa de Desenvolvedores Apple

O Sign In with Apple só pode ser configurado por membros do Apple Developer Program .

Configurar login com Apple

O login da Apple deve estar ativado e configurado corretamente em seu projeto do Firebase. A configuração varia entre as plataformas Android e Apple. Siga a seção "Configurar login com a Apple" dos guias das plataformas Apple e/ou Android antes de continuar.

Habilite a Apple como provedor de login

  1. No console do Firebase , abra a seção Auth . Na guia Método de login , habilite o provedor Apple .
  2. Defina as configurações do provedor de login da Apple:
    1. Se você estiver implantando seu aplicativo apenas em plataformas Apple, poderá deixar os campos ID do serviço, ID da equipe Apple, chave privada e ID da chave vazios.
    2. Para suporte em dispositivos Android:
      1. Adicione o Firebase ao seu projeto Android . Certifique-se de registrar a assinatura SHA-1 do seu aplicativo ao configurá-lo no Console do Firebase.
      2. No console do Firebase , abra a seção Auth . Na guia Método de login , habilite o provedor Apple . Especifique o ID do serviço que você criou na seção anterior. Além disso, na seção de configuração do fluxo de código OAuth, especifique seu Apple Team ID e a chave privada e o ID de chave que você criou na seção anterior.

Cumpra os requisitos de dados anonimizados da Apple

Sign In with Apple oferece aos usuários a opção de anonimizar seus dados, incluindo seu endereço de e-mail, ao fazer login. Os usuários que escolhem esta opção possuem endereços de e-mail com o domínio privaterelay.appleid.com . Ao usar o Sign In with Apple em seu aplicativo, você deve cumprir quaisquer políticas ou termos de desenvolvedor aplicáveis ​​da Apple em relação a esses IDs Apple anônimos.

Isso inclui obter qualquer consentimento necessário do usuário antes de associar qualquer informação pessoal de identificação direta a um ID Apple anônimo. Ao usar o Firebase Authentication, isso pode incluir as seguintes ações:

  • Vincule um endereço de e-mail a um ID Apple anônimo ou vice-versa.
  • Vincule um número de telefone a um ID Apple anônimo ou vice-versa
  • Vincule uma credencial social não anônima (Facebook, Google, etc.) a um ID Apple anônimo ou vice-versa.

A lista acima não é exaustiva. Consulte o Contrato de licença do Apple Developer Program na seção Assinatura da sua conta de desenvolvedor para garantir que seu aplicativo atenda aos requisitos da Apple.

Acesse a classe firebase::auth::Auth

A classe Auth é o gateway para todas as chamadas de API.
  1. Adicione os arquivos de cabeçalho Auth e App:
    #include "firebase/app.h"
    #include "firebase/auth.h"
  2. No seu código de inicialização, crie uma classe 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__)
  3. Adquira a classe firebase::auth::Auth para seu firebase::App . Há um mapeamento individual entre App e Auth .
    firebase::auth::Auth* auth = firebase::auth::Auth::GetAuth(app);

Lidar com o fluxo de login com o SDK do Firebase

O processo para fazer login na Apple varia entre as plataformas Apple e Android.

Nas plataformas Apple

Autentique seus usuários com o Firebase por meio do SDK Apple Sign In Objective-C invocado a partir do seu código C++.

  1. Para cada solicitação de login, gere uma string aleatória — um "nonce" — que você usará para garantir que o token de ID obtido foi concedido especificamente em resposta à solicitação de autenticação do seu aplicativo. Esta etapa é importante para evitar ataques de repetição.

      - (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
    --;
           
    }
         
    }
       
    }
     
    }

    Você enviará o hash SHA256 do nonce com sua solicitação de login, que a Apple transmitirá inalterada na resposta. O Firebase valida a resposta fazendo hash do nonce original e comparando-o com o valor passado pela Apple.

  2. Inicie o fluxo de login da Apple, incluindo na sua solicitação o hash SHA256 do nonce e a classe delegada que tratará a resposta da Apple (veja o próximo passo):

      - (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;
     
    }
  3. Lide com a resposta da Apple na sua implementação de ASAuthorizationControllerDelegate`. Se o login for bem-sucedido, use o token de ID da resposta da Apple com o nonce sem hash para autenticar no 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);
         
    }
       
    }
  4. Use a string de token resultante e o nonce original para construir uma credencial do Firebase e fazer login no Firebase.

    firebase::auth::OAuthProvider::GetCredential(
           
    /*provider_id=*/"apple.com", token, nonce,
           
    /*access_token=*/nullptr);

    firebase
    ::Future<firebase::auth::AuthResult> result =
        auth
    ->SignInAndRetrieveDataWithCredential(credential);
  5. O mesmo padrão pode ser usado com Reauthenticate , que pode ser usado para recuperar credenciais novas para operações confidenciais que exigem login recente.

    firebase::Future<firebase::auth::AuthResult> result =
        user
    ->Reauthenticate(credential);
  6. O mesmo padrão pode ser usado para vincular uma conta ao Apple Sign In. No entanto, você pode encontrar um erro quando uma conta existente do Firebase já tiver sido vinculada à conta Apple à qual você está tentando vincular. Quando isso ocorrer, o futuro retornará um status kAuthErrorCredentialAlreadyInUse e o AuthResult poderá conter uma credential válida. Essa credencial pode ser usada para fazer login na conta vinculada à Apple por meio de SignInAndRetrieveDataWithCredential sem a necessidade de gerar outro token de login da Apple e nonce.

    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.
    }

No Android

No Android, autentique seus usuários com o Firebase integrando o login OAuth genérico baseado na Web ao seu aplicativo usando o SDK do Firebase para realizar o fluxo de login de ponta a ponta.

Para lidar com o fluxo de login com o SDK do Firebase, siga estas etapas:

  1. Construa uma instância de FederatedOAuthProviderData configurada com o ID do provedor apropriado para Apple.

    firebase::auth::FederatedOAuthProviderData provider_data("apple.com");
  2. Opcional: Especifique escopos adicionais do OAuth 2.0 além do padrão que você deseja solicitar do provedor de autenticação.

    provider_data.scopes.push_back("email");
    provider_data
    .scopes.push_back("name");
  3. Opcional: se desejar exibir a tela de login da Apple em um idioma diferente do inglês, defina o parâmetro locale . Consulte os documentos Sign In with Apple para obter as localidades suportadas.

    // Localize to French.
    provider_data
    .custom_parameters["language"] = "fr";
    ```
  4. Depois que os dados do seu provedor forem configurados, use-os para criar um FederatedOAuthProvider.

    // Construct a FederatedOAuthProvider for use in Auth methods.
    firebase
    ::auth::FederatedOAuthProvider provider(provider_data);
  5. Autentique-se com o Firebase usando o objeto do provedor Auth. Observe que, diferentemente de outras operações do FirebaseAuth, isso assumirá o controle da sua IU, exibindo uma visualização da web na qual o usuário pode inserir suas credenciais.

    Para iniciar o fluxo de login, chame signInWithProvider :

    firebase::Future<firebase::auth::AuthResult> result =
      auth
    ->SignInWithProvider(provider_data);

    Seu aplicativo poderá então aguardar ou registrar um retorno de chamada no Future .

  6. O mesmo padrão pode ser usado com ReauthenticateWithProvider , que pode ser usado para recuperar novas credenciais para operações confidenciais que exigem login recente.

    firebase::Future<firebase::auth::AuthResult> result =
      user
    .ReauthenticateWithProvider(provider_data);

    Seu aplicativo poderá então aguardar ou registrar um retorno de chamada no Future .

  7. E você pode usar LinkWithCredential() para vincular diferentes provedores de identidade a contas existentes.

    Observe que a Apple exige que você obtenha o consentimento explícito dos usuários antes de vincular suas contas Apple a outros dados.

    Por exemplo, para vincular uma conta do Facebook à conta atual do Firebase, use o token de acesso obtido ao fazer login do usuário no 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);

Faça login com o Apple Notes

Ao contrário de outros provedores suportados pelo Firebase Auth, a Apple não fornece um URL de foto.

Além disso, quando o usuário opta por não compartilhar seu e-mail com o aplicativo, a Apple fornece um endereço de e-mail exclusivo para esse usuário (no formato xyz@privaterelay.appleid.com ), que ele compartilha com seu aplicativo. Se você configurou o serviço de retransmissão de e-mail privado, a Apple encaminha os e-mails enviados para o endereço anônimo para o endereço de e-mail real do usuário.

A Apple só compartilha informações do usuário, como o nome de exibição, com os aplicativos na primeira vez que um usuário faz login. Normalmente, o Firebase armazena o nome de exibição na primeira vez que um usuário faz login na Apple, que você pode obter com current_user().display_name() . No entanto, se você usou anteriormente a Apple para fazer login de um usuário no aplicativo sem usar o Firebase, a Apple não fornecerá ao Firebase o nome de exibição do usuário.

Próximos passos

Depois que um usuário faz login pela primeira vez, uma nova conta de usuário é criada e vinculada às credenciais (ou seja, nome de usuário e senha, número de telefone ou informações do provedor de autenticação) com as quais o usuário fez login. Essa nova conta é armazenada como parte do seu projeto do Firebase e pode ser usada para identificar um usuário em todos os aplicativos do seu projeto, independentemente de como o usuário faz login.

Nos seus aplicativos, você pode obter as informações básicas do perfil do usuário no objeto firebase::auth::User . Consulte Gerenciar usuários .

Nas regras de segurança do Firebase Realtime Database e do Cloud Storage, você pode obter o ID de usuário exclusivo do usuário conectado na variável auth e usá-lo para controlar quais dados um usuário pode acessar.