Autenticar usando Apple e C ++

Você pode usar o SDK do Firebase para permitir que os usuários façam a autenticação com o Firebase usando o ID Apple para realizar todo o fluxo de login do OAuth 2.0.

Antes de começar

Para fazer login de usuários usando a Apple, primeiro configure o recurso Iniciar sessão com a Apple no site do desenvolvedor da Apple e ative-a como um provedor de login para seu projeto do Firebase.

Participe do Programa para desenvolvedores da Apple

O recurso Iniciar sessão com a Apple só pode ser configurado por membros do Programa para desenvolvedores da Apple.

Configurar o recurso "Iniciar sessão com a Apple"

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

Ativar a Apple como um provedor de login

  1. No Console do Firebase, abra a seção Auth. Na guia Método de login, ative o provedor Apple.
  2. Definir as configurações do provedor de login da Apple:
    1. Se você estiver implantando seu aplicativo apenas em plataformas Apple, deixe os campos "ID do serviço", "ID da equipe da Apple", "Chave privada" e "ID da chave" vazios.
    2. Para suporte em dispositivos Android:
      1. Adicione o Firebase ao projeto do Android. Não esqueça de registrar a assinatura SHA-1 do seu aplicativo ao configurar o aplicativo no Console do Firebase.
      2. No Console do Firebase, abra a seção Auth. Na guia Método de login, ative 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 do OAuth, especifique o ID de equipe da Apple, a chave privada e o ID da chave que você criou na seção anterior.

Obedeça aos requisitos de dados anônimos da Apple

O recurso Iniciar sessão com a Apple permite que os usuários decidam se querem que seus dados fiquem anônimos, incluindo o endereço de e-mail, ao fazer login. Os usuários que escolhem essa opção têm endereços de e-mail com o domínio privaterelay.appleid.com. Ao usar o recurso Iniciar sessão com a Apple no seu aplicativo, você precisa estar em conformidade com todos os termos ou políticas do desenvolvedor aplicáveis da Apple relacionados a esses IDs anônimos da Apple.

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

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

Essa não é uma lista completa. Consulte o Contrato de licença do programa para desenvolvedores da Apple na seção de associação da sua conta de desenvolvedor para verificar se o aplicativo atende aos requisitos da Apple.

Acessar 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 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 de um para um entre App e Auth.
    firebase::auth::Auth* auth = firebase::auth::Auth::GetAuth(app);
    

Processar o fluxo de login com o SDK do Firebase

O processo do recurso Iniciar sessão com a Apple varia entre plataformas Apple e Android.

Em plataformas da Apple

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

  1. Para cada solicitação de login, gere uma string aleatória, um "valor de uso único", que será usada para garantir que o token de código recebido seja concedido especificamente em resposta à solicitação de autenticação do aplicativo. Essa etapa é importante para evitar ataques repetidos.

      - (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 valor de uso único com sua solicitação de login, que a Apple não fará alterações na resposta. O Firebase valida a resposta gerando a hash do valor de uso único original e comparando-a ao valor transmitido pela Apple.

  2. Inicie o fluxo de login da Apple, incluindo na solicitação a hash SHA256 do valor de uso único e a classe delegada que processará a resposta da Apple (consulte a próxima etapa):

      - (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. Processe a resposta da Apple na sua implementação de ASAuthorizationControllerDelegate`. Se o login for bem-sucedido, use o token de código da resposta da Apple com o valor de uso único sem hash para autenticar com o 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 valor de uso único original para criar uma credencial do Firebase e fazer login na plataforma.

    firebase::auth::OAuthProvider::GetCredential(
            /*provider_id=*/"apple.com", token, nonce,
            /*access_token=*/nullptr);
    
    firebase::Future<firebase::auth::AuthResult> result =
        auth->SignInAndRetrieveDataWithCredential(credential);
    
  5. É possível usar o mesmo padrão com Reauthenticate, que pode ser utilizado para recuperar credenciais novas de operações confidenciais que exigem um login recente.

    firebase::Future<firebase::auth::AuthResult> result =
        user->Reauthenticate(credential);
    
  6. O mesmo padrão pode ser usado para vincular uma conta ao login da Apple. No entanto, é possível visualizar um erro quando uma conta do Firebase já foi vinculada à conta da Apple que você está tentando vincular. Quando isso ocorrer, o futuro vai retornar um status de kAuthErrorCredentialAlreadyInUse e o AuthResult poderá ter um credential válido. Essa credencial pode ser usada para fazer login na conta vinculada à Apple usando o SignInAndRetrieveDataWithCredential sem precisar gerar outro token de login da Apple e um valor de uso único.

    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 app usando o SDK do Firebase para realizar o fluxo de login completo.

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

  1. Crie uma instância de um FederatedOAuthProviderData configurado com o ID do provedor apropriado para a Apple.

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

    provider_data.scopes.push_back("email");
    provider_data.scopes.push_back("name");
    
  3. Opcional: se você quiser mostrar a tela de login da Apple em um idioma diferente do inglês, configure o parâmetro locale. Consulte Fazer login com os documentos da Apple para ver as localidades compatíveis.

    // Localize to French.
    provider_data.custom_parameters["language"] = "fr";
    ```
    
  4. Depois de configurar os dados do provedor, 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 de provedor Auth. Ao contrário de outras operações do FirebaseAuth, isso assumirá o controle da IU exibindo uma visualização da Web na qual o usuário pode inserir as credenciais.

    Para iniciar o fluxo de login, chame signInWithProvider:

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

    Seu aplicativo pode aguardar ou registrar um callback no Future.

  6. É possível usar o mesmo padrão com ReauthenticateWithProvider, que pode ser utilizado para recuperar credenciais novas de operações confidenciais que exigem um login recente.

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

    Seu aplicativo pode aguardar ou registrar um callback no Future.

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

    Observe que a Apple exige que você tenha consentimento explícito dos usuários antes de vincular as contas da Apple a outros dados.

    Por exemplo, para vincular uma conta do Facebook à conta atual do Firebase, use o token de acesso de início de sessão 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);
    

Fazer login com o Notas

Diferentemente de outros provedores compatíveis com o Firebase Auth, a Apple não fornece um URL de foto.

Além disso, quando o usuário opta por não compartilhar e-mails com o app, a Apple fornece um endereço de e-mail exclusivo para esse usuário, no formato xyz@privaterelay.appleid.com, que compartilha com seu app. Se você tiver configurado o serviço de retransmissão de e-mail privado, os e-mails enviados ao endereço anônimo serão encaminhados pela Apple 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 apps 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 com a Apple, que você pode usar com current_user().display_name(). No entanto, se você já usou a Apple para fazer login de um usuário no app sem usar o Firebase, a Apple não vai fornecer ao Firebase o nome de exibição do usuário.

Próximas etapas

Depois que um usuário faz login pela primeira vez, uma nova conta de usuário é criada e vinculada às credenciais, que podem ser o número do telefone, o nome de usuário e a senha ou as informações do provedor de autenticação. Essa nova conta é armazenada como parte do projeto do Firebase e pode ser usada para identificar um usuário em todos os apps do projeto, seja qual for o método de login utilizado.

É possível receber as informações básicas de perfil do usuário do objeto firebase::auth::User nos seus aplicativos. Consulte Gerenciar usuários.

Nas Regras de segurança do Firebase Realtime Database e do Cloud Storage, é possível usar a variável auth para encontrar o ID exclusivo do usuário conectado. Utilize essa informação para controlar o acesso dele aos dados.