Como adicionar a autenticação multifator ao seu app para iOS
Este documento mostra como adicionar a autenticação multifator por SMS ao seu app iOS.
A autenticação multifator aumenta a segurança do app. Os invasores costumam comprometer as senhas e contas de redes sociais, mas é mais difícil interceptar uma mensagem de texto.
Antes de começar
Ative pelo menos um provedor compatível com a autenticação multifator. Todos os provedores são compatíveis com a autenticação multifator (MFA), exceto as autenticações por smartphone e a anônima e o Apple Game Center.
Confirme se o app está verificando os e-mails do usuário. A autenticação multifator (MFA) requer verificação de e-mail. Isso impede que agentes mal-intencionados se registrem em um serviço com um e-mail que não tenham e bloqueiem o proprietário real adicionando um segundo fator.
Como ativar a autenticação multifator
Acesse a página MFA do Identity Platform no console do Google Cloud.
Acessar a página MFANa caixa Autenticação de vários fatores baseada em SMS, clique em Ativar.
Insira os números de telefone com os quais você testará seu aplicativo. Ainda que seja opcional, é altamente recomendável registrar números de telefone de teste para evitar a limitação durante o desenvolvimento.
Se você ainda não autorizou o domínio do seu aplicativo, adicione-o à lista de permissões clicando em Adicionar domínio à direita.
Clique em Save.
Como verificar seu aplicativo
O Identity Platform precisa verificar se as solicitações de SMS são provenientes do app. É possível fazer isso de duas maneiras:
Notificações de APNs silenciosas: quando você faz login em um usuário pela primeira vez, o Identity Platform pode enviar uma notificação push silenciosa para o dispositivo do usuário. A autenticação poderá continuar se o app receber a notificação. No iOS 8.0 e versões mais recentes, não é necessário solicitar ao usuário que permita notificações push para usar esse método.
Verificação reCAPTCHA: se não for possível enviar uma notificação silenciosa (por exemplo, porque o usuário desativou a atualização em segundo plano ou você está testando seu app no simulador do iOS), use o reCAPTCHA. Em muitos casos, o reCAPTCHA será resolvido automaticamente sem interação do usuário.
Como usar notificações silenciosas
Para ativar notificações de APNs para uso com o Identity Platform:
No Xcode, ative as notificações push para seu projeto.
Faça upload da chave de autenticação de APNs usando o Console do Firebase. Suas alterações serão automaticamente transferidas para o Google Cloud Identity Platform. Se você ainda não tem a chave de autenticação de APNs, consulte Como configurar APNs com o FCM para saber como recebê-la.
Abra o Console do Firebase.
Navegue até Configurações do projeto.
Selecione a guia Cloud Messaging.
Em Chave de autenticação de APNs, na seção Configuração do app para iOS, clique em Fazer upload.
Selecione a chave.
Adicione o ID da chave. Encontre o ID da chave em Certificados, identificadores e perfis na Apple Developer Member Center.
Clique em Upload.
Se você já tem um certificado de APNs, é possível fazer o upload dele em vez disso.
Como usar a verificação reCAPTCHA
Para ativar o SDK do cliente e usar o reCAPTCHA. faça o seguinte:
Abra a configuração do seu projeto no Xcode.
Clique duas vezes no nome do projeto na visualização em árvore à esquerda.
Selecione seu app na seção Destinos.
Selecione a guia Informações.
Expanda a seção Tipos de URL.
Clique no botão +.
Insira o ID do cliente revertido no campo URL esquemas de gerenciamento. Esse valor está listado no arquivo de configuração
GoogleService-Info.plist
comoREVERSED_CLIENT_ID
.
Quando concluída, a configuração será semelhante a esta:
Também é possível personalizar a forma como o app apresenta o
SFSafariViewController
ou o UIWebView
ao exibir o reCAPTCHA. Para fazer
isso, crie uma classe personalizada que esteja em conformidade com o protocolo
FIRAuthUIDelegate
e transmita-a para verifyPhoneNumber:UIDelegate:completion:
.
Como escolher um padrão de inscrição
É possível escolher se o app requer autenticação multifator e como e quando registrar os usuários. Alguns padrões comuns incluem:
Registrar o segundo fator do usuário como parte do processo. Use esse método se o app exigir autenticação multifator para todos os usuários. Observe que uma conta precisa ter um endereço de e-mail verificado para registrar um segundo fator. Portanto, seu fluxo de registro terá que acomodar isso.
Oferecer uma opção que pode ser ignorada para registrar um segundo fator durante o processo. Os apps que quiserem incentivar, mas não exigirem, a autenticação multifator terão essa abordagem.
Permitir a adição de um segundo fator na página de gerenciamento da conta ou no perfil do usuário, em vez da tela de inscrição. Isso minimiza o atrito durante o processo de registro, ao mesmo tempo que disponibiliza a autenticação multifator para usuários que se preocupam com a segurança.
Exigir a adição de um segundo fator de maneira incremental quando o usuário quiser acessar recursos com requisitos de segurança aprimorados.
Como registrar um segundo fator
Para registrar um novo fator secundário para um usuário:
Reautentique o usuário.
Peça ao usuário para inserir o número de telefone.
Receba uma sessão de vários fatores para o usuário:
Swift
authResult.user.multiFactor.getSessionWithCompletion() { (session, error) in // ... }
Objective-C
[authResult.user.multiFactor getSessionWithCompletion:^(FIRMultiFactorSession * _Nullable session, NSError * _Nullable error) { // ... }];
Envie uma mensagem de verificação ao smartphone do usuário. Verifique se o número de telefone está formatado com
+
no começo e sem outros sinais de pontuação ou espaços em branco (por exemplo:+15105551234
).Swift
// Send SMS verification code. PhoneAuthProvider.provider().verifyPhoneNumber( phoneNumber, uiDelegate: nil, multiFactorSession: session) { (verificationId, error) in // verificationId will be needed for enrollment completion. }
Objective-C
// Send SMS verification code. [FIRPhoneAuthProvider.provider verifyPhoneNumber:phoneNumber UIDelegate:nil multiFactorSession:session completion:^(NSString * _Nullable verificationID, NSError * _Nullable error) { // verificationId will be needed for enrollment completion. }];
Ainda que não seja obrigatório, é uma prática recomendada informar aos usuários antecipadamente que eles receberão uma mensagem SMS e quais taxas padrão serão aplicadas.
O método
verifyPhoneNumber()
inicia o processo de verificação do app em segundo plano usando a notificação push silenciosa. Se a notificação push silenciosa não estiver disponível, um desafio reCAPTCHA será emitido.Após o envio do código SMS, peça ao usuário para fazer a verificação. Em seguida, use a resposta dele para criar um
PhoneAuthCredential
:Swift
// Ask user for the verification code. Then: let credential = PhoneAuthProvider.provider().credential( withVerificationID: verificationId, verificationCode: verificationCode)
Objective-C
// Ask user for the SMS verification code. Then: FIRPhoneAuthCredential *credential = [FIRPhoneAuthProvider.provider credentialWithVerificationID:verificationID verificationCode:kPhoneSecondFactorVerificationCode];
Inicialize um objeto de declaração:
Swift
let assertion = PhoneMultiFactorGenerator.assertion(with: credential)
Objective-C
FIRMultiFactorAssertion *assertion = [FIRPhoneMultiFactorGenerator assertionWithCredential:credential];
Conclua a inscrição. Se quiser, especifique um nome de exibição para o segundo fator. Isso é útil para usuários com vários fatores, já que o número de telefone é mascarado durante o fluxo de autenticação (por exemplo, +1******1234).
Swift
// Complete enrollment. This will update the underlying tokens // and trigger ID token change listener. user.multiFactor.enroll(with: assertion, displayName: displayName) { (error) in // ... }
Objective-C
// Complete enrollment. This will update the underlying tokens // and trigger ID token change listener. [authResult.user.multiFactor enrollWithAssertion:assertion displayName:nil completion:^(NSError * _Nullable error) { // ... }];
O código abaixo mostra um exemplo completo de inscrição de um segundo fator:
Swift
let user = Auth.auth().currentUser
user?.multiFactor.getSessionWithCompletion({ (session, error) in
// Send SMS verification code.
PhoneAuthProvider.provider().verifyPhoneNumber(
phoneNumber,
uiDelegate: nil,
multiFactorSession: session
) { (verificationId, error) in
// verificationId will be needed for enrollment completion.
// Ask user for the verification code.
let credential = PhoneAuthProvider.provider().credential(
withVerificationID: verificationId!,
verificationCode: phoneSecondFactorVerificationCode)
let assertion = PhoneMultiFactorGenerator.assertion(with: credential)
// Complete enrollment. This will update the underlying tokens
// and trigger ID token change listener.
user?.multiFactor.enroll(with: assertion, displayName: displayName) { (error) in
// ...
}
}
})
Objective-C
FIRUser *user = FIRAuth.auth.currentUser;
[user.multiFactor getSessionWithCompletion:^(FIRMultiFactorSession * _Nullable session,
NSError * _Nullable error) {
// Send SMS verification code.
[FIRPhoneAuthProvider.provider
verifyPhoneNumber:phoneNumber
UIDelegate:nil
multiFactorSession:session
completion:^(NSString * _Nullable verificationID, NSError * _Nullable error) {
// verificationId will be needed for enrollment completion.
// Ask user for the verification code.
// ...
// Then:
FIRPhoneAuthCredential *credential =
[FIRPhoneAuthProvider.provider credentialWithVerificationID:verificationID
verificationCode:kPhoneSecondFactorVerificationCode];
FIRMultiFactorAssertion *assertion =
[FIRPhoneMultiFactorGenerator assertionWithCredential:credential];
// Complete enrollment. This will update the underlying tokens
// and trigger ID token change listener.
[user.multiFactor enrollWithAssertion:assertion
displayName:displayName
completion:^(NSError * _Nullable error) {
// ...
}];
}];
}];
Parabéns! Você registrou um segundo fator de autenticação para um usuário.
Como fazer login dos usuários com um segundo fator
Para fazer login de um usuário com verificação por SMS de dois fatores:
Faça o login do usuário com o primeiro fator e, em seguida, capture um erro indicando que a autenticação multifator é necessária. Esse erro contém um resolvedor, dicas sobre os dois fatores registrados e uma sessão subjacente que mostra que o usuário foi autenticado com êxito com o primeiro fator.
Por exemplo, se o primeiro fator do usuário for um e-mail e uma senha:
Swift
Auth.auth().signIn( withEmail: email, password: password ) { (result, error) in let authError = error as NSError if authError?.code == AuthErrorCode.secondFactorRequired.rawValue { // The user is a multi-factor user. Second factor challenge is required. let resolver = authError!.userInfo[AuthErrorUserInfoMultiFactorResolverKey] as! MultiFactorResolver // ... } else { // Handle other errors such as wrong password. } }
Objective-C
[FIRAuth.auth signInWithEmail:email password:password completion:^(FIRAuthDataResult * _Nullable authResult, NSError * _Nullable error) { if (error == nil || error.code != FIRAuthErrorCodeSecondFactorRequired) { // User is not enrolled with a second factor and is successfully signed in. // ... } else { // The user is a multi-factor user. Second factor challenge is required. } }];
Se o primeiro fator do usuário for um provedor federado, como o OAuth, capture o erro depois de chamar
getCredentialWith()
.Se o usuário tiver vários fatores secundários registrados, pergunte a ele qual usar. É possível conseguir o número de telefone mascarado com
resolver.hints[selectedIndex].phoneNumber
e o nome de exibição comresolver.hints[selectedIndex].displayName
.Swift
// Ask user which second factor to use. Then: if resolver.hints[selectedIndex].factorID == PhoneMultiFactorID { // User selected a phone second factor. // ... } else if resolver.hints[selectedIndex].factorID == TotpMultiFactorID { // User selected a TOTP second factor. // ... } else { // Unsupported second factor. }
Objective-C
FIRMultiFactorResolver *resolver = (FIRMultiFactorResolver *) error.userInfo[FIRAuthErrorUserInfoMultiFactorResolverKey]; // Ask user which second factor to use. Then: FIRPhoneMultiFactorInfo *hint = (FIRPhoneMultiFactorInfo *) resolver.hints[selectedIndex]; if (hint.factorID == FIRPhoneMultiFactorID) { // User selected a phone second factor. // ... } else if (hint.factorID == FIRTOTPMultiFactorID) { // User selected a TOTP second factor. // ... } else { // Unsupported second factor. }
Enviar uma mensagem de verificação para o telefone do usuário:
Swift
// Send SMS verification code. let hint = resolver.hints[selectedIndex] as! PhoneMultiFactorInfo PhoneAuthProvider.provider().verifyPhoneNumber( with: hint, uiDelegate: nil, multiFactorSession: resolver.session ) { (verificationId, error) in // verificationId will be needed for sign-in completion. }
Objective-C
// Send SMS verification code [FIRPhoneAuthProvider.provider verifyPhoneNumberWithMultiFactorInfo:hint UIDelegate:nil multiFactorSession:resolver.session completion:^(NSString * _Nullable verificationID, NSError * _Nullable error) { if (error != nil) { // Failed to verify phone number. } }];
Depois que o código SMS for enviado, peça ao usuário para verificar o código e usá-lo para criar um
PhoneAuthCredential
:Swift
// Ask user for the verification code. Then: let credential = PhoneAuthProvider.provider().credential( withVerificationID: verificationId!, verificationCode: verificationCodeFromUser)
Objective-C
// Ask user for the SMS verification code. Then: FIRPhoneAuthCredential *credential = [FIRPhoneAuthProvider.provider credentialWithVerificationID:verificationID verificationCode:verificationCodeFromUser];
Inicialize um objeto de declaração com a credencial:
Swift
let assertion = PhoneMultiFactorGenerator.assertion(with: credential)
Objective-C
FIRMultiFactorAssertion *assertion = [FIRPhoneMultiFactorGenerator assertionWithCredential:credential];
Resolva o login. Em seguida, você pode acessar o resultado do login original, que inclui os dados padrão do provedor e as credenciais de autenticação:
Swift
// Complete sign-in. This will also trigger the Auth state listeners. resolver.resolveSignIn(with: assertion) { (authResult, error) in // authResult will also contain the user, additionalUserInfo, optional // credential (null for email/password) associated with the first factor sign-in. // For example, if the user signed in with Google as a first factor, // authResult.additionalUserInfo will contain data related to Google provider that // the user signed in with. // user.credential contains the Google OAuth credential. // user.credential.accessToken contains the Google OAuth access token. // user.credential.idToken contains the Google OAuth ID token. }
Objective-C
// Complete sign-in. [resolver resolveSignInWithAssertion:assertion completion:^(FIRAuthDataResult * _Nullable authResult, NSError * _Nullable error) { if (error != nil) { // User successfully signed in with the second factor phone number. } }];
O código abaixo mostra um exemplo completo de login em um usuário de vários fatores:
Swift
Auth.auth().signIn(
withEmail: email,
password: password
) { (result, error) in
let authError = error as NSError?
if authError?.code == AuthErrorCode.secondFactorRequired.rawValue {
let resolver =
authError!.userInfo[AuthErrorUserInfoMultiFactorResolverKey] as! MultiFactorResolver
// Ask user which second factor to use.
// ...
// Then:
let hint = resolver.hints[selectedIndex] as! PhoneMultiFactorInfo
// Send SMS verification code
PhoneAuthProvider.provider().verifyPhoneNumber(
with: hint,
uiDelegate: nil,
multiFactorSession: resolver.session
) { (verificationId, error) in
if error != nil {
// Failed to verify phone number.
}
// Ask user for the SMS verification code.
// ...
// Then:
let credential = PhoneAuthProvider.provider().credential(
withVerificationID: verificationId!,
verificationCode: verificationCodeFromUser)
let assertion = PhoneMultiFactorGenerator.assertion(with: credential)
// Complete sign-in.
resolver.resolveSignIn(with: assertion) { (authResult, error) in
if error != nil {
// User successfully signed in with the second factor phone number.
}
}
}
}
}
Objective-C
[FIRAuth.auth signInWithEmail:email
password:password
completion:^(FIRAuthDataResult * _Nullable authResult,
NSError * _Nullable error) {
if (error == nil || error.code != FIRAuthErrorCodeSecondFactorRequired) {
// User is not enrolled with a second factor and is successfully signed in.
// ...
} else {
FIRMultiFactorResolver *resolver =
(FIRMultiFactorResolver *) error.userInfo[FIRAuthErrorUserInfoMultiFactorResolverKey];
// Ask user which second factor to use.
// ...
// Then:
FIRPhoneMultiFactorInfo *hint = (FIRPhoneMultiFactorInfo *) resolver.hints[selectedIndex];
// Send SMS verification code
[FIRPhoneAuthProvider.provider
verifyPhoneNumberWithMultiFactorInfo:hint
UIDelegate:nil
multiFactorSession:resolver.session
completion:^(NSString * _Nullable verificationID,
NSError * _Nullable error) {
if (error != nil) {
// Failed to verify phone number.
}
// Ask user for the SMS verification code.
// ...
// Then:
FIRPhoneAuthCredential *credential =
[FIRPhoneAuthProvider.provider
credentialWithVerificationID:verificationID
verificationCode:kPhoneSecondFactorVerificationCode];
FIRMultiFactorAssertion *assertion =
[FIRPhoneMultiFactorGenerator assertionWithCredential:credential];
// Complete sign-in.
[resolver resolveSignInWithAssertion:assertion
completion:^(FIRAuthDataResult * _Nullable authResult,
NSError * _Nullable error) {
if (error != nil) {
// User successfully signed in with the second factor phone number.
}
}];
}];
}
}];
Parabéns! Você fez login com sucesso usando uma autenticação multifator.
A seguir
- Gerencie usuários de vários fatores programaticamente com o SDK Admin.