Adicionar autenticação multifator à sua app iOS
Este documento mostra como adicionar a autenticação multifator por SMS à sua app iOS.
A autenticação multifator aumenta a segurança da sua app. Embora os atacantes comprometam frequentemente palavras-passe e contas sociais, intercetar uma mensagem de texto é mais difícil.
Antes de começar
Ative, pelo menos, um fornecedor que suporte a autenticação multifator. Todos os fornecedores suportam a MFA, exceto a autenticação por telefone, a autenticação anónima e o Game Center da Apple.
Certifique-se de que a sua app está a validar os emails dos utilizadores. A MFA requer validação por email. Isto impede que pessoas com intenções maliciosas se registem num serviço com um email que não lhes pertence e, em seguida, bloqueiem o proprietário real adicionando um segundo fator.
Ativar a autenticação multifator
Aceda à página MFA do Identity Platform na Google Cloud consola.
Aceda à página da MFANa caixa com o título Autenticação multifator baseada em SMS, clique em Ativar.
Introduza os números de telefone com os quais vai testar a sua app. Embora seja opcional, é vivamente recomendada a registo de números de telefone de teste para evitar a limitação durante o desenvolvimento.
Se ainda não tiver autorizado o domínio da sua app, adicione-o à lista de autorizações clicando em Adicionar domínio à direita.
Clique em Guardar.
Validar a sua app
A Identity Platform tem de validar se os pedidos de SMS estão a ser enviados a partir da sua app. Pode fazê-lo de duas formas:
Notificações APNs silenciosas: quando um utilizador inicia sessão pela primeira vez, a Identity Platform pode enviar uma notificação push silenciosa para o dispositivo do utilizador. A autenticação pode continuar se a app receber a notificação. Tenha em atenção que, a partir do iOS 8.0, não precisa de pedir ao utilizador que permita as notificações push para usar este método.
Validação reCAPTCHA: se não conseguir enviar uma notificação silenciosa (por exemplo, porque o utilizador desativou a atualização em segundo plano ou está a testar a sua app no simulador do iOS), pode usar o reCAPTCHA. Em muitos casos, o reCAPTCHA resolve-se automaticamente sem interação do utilizador.
Usar notificações silenciosas
Para ativar as notificações APNs para utilização com a Identity Platform:
No Xcode, ative as notificações push para o seu projeto.
Carregue a chave de autenticação dos APNs através da consola do Firebase (as alterações são automaticamente transferidas para a Google Cloud Identity Platform). Se ainda não tiver a chave de autenticação do APNs, consulte o artigo Configurar o APNs com o FCM para saber como obtê-la.
Abra a consola do Firebase.
Navegue para Definições do projeto.
Selecione o separador Cloud Messaging.
Em Chave de autenticação APNs, na secção Configuração da app iOS, clique em Carregar para carregar a chave de autenticação de desenvolvimento, a chave de autenticação de produção ou ambas. É necessário, no mínimo, um desses dados.
Selecione a chave.
Adicione o ID da chave. Pode encontrar o ID da chave em Certificados, identificadores e perfis no Apple Developer Member Center.
Clique em Carregar.
Se já tiver um certificado de APNs, pode carregá-lo.
Usar a validação reCAPTCHA
Para permitir que o SDK de cliente use o reCAPTCHA:
Abra a configuração do projeto no Xcode.
Clique duas vezes no nome do projeto na vista de árvore do lado esquerdo.
Selecione a sua app na secção Segmentos.
Selecione o separador Informações.
Expanda a secção Tipos de URLs.
Clique no botão +.
Introduza o ID de cliente invertido no campo Esquemas de URL. Pode encontrar este valor indicado no ficheiro de configuração
GoogleService-Info.plist
comoREVERSED_CLIENT_ID
.
Quando estiver concluída, a configuração deve ser semelhante à seguinte:
Opcionalmente, pode personalizar a forma como a sua app apresenta o ícone
SFSafariViewController
ou UIWebView
quando apresenta o reCAPTCHA. Para o fazer, crie uma classe personalizada em conformidade com o protocolo FIRAuthUIDelegate
e transmita-a para verifyPhoneNumber:UIDelegate:completion:
.
Escolher um padrão de inscrição
Pode escolher se a sua app requer autenticação multifator e como e quando inscrever os seus utilizadores. Alguns padrões comuns incluem:
Inscrever o segundo fator do utilizador como parte do registo. Use este método se a sua app exigir a autenticação multifator para todos os utilizadores. Tenha em atenção que uma conta tem de ter um endereço de email validado para inscrever um segundo fator, pelo que o seu fluxo de registo tem de ter isto em conta.
Ofereça uma opção ignorável para inscrever um segundo fator durante o registo. As apps que querem incentivar, mas não exigir, a autenticação multifator podem preferir esta abordagem.
Oferecer a capacidade de adicionar um segundo fator a partir da página de gestão do perfil ou da conta do utilizador, em vez do ecrã de inscrição. Isto minimiza as complicações durante o processo de registo, ao mesmo tempo que disponibiliza a autenticação multifator para utilizadores sensíveis à segurança.
Exigir a adição de um segundo fator de forma incremental quando o utilizador quiser aceder a funcionalidades com requisitos de segurança aumentados.
Inscrever um segundo fator
Para inscrever um novo fator secundário para um utilizador:
Volte a autenticar o utilizador.
Peça ao utilizador para introduzir o respetivo número de telefone.
Obtenha uma sessão multifator para o utilizador:
Swift
authResult.user.multiFactor.getSessionWithCompletion() { (session, error) in // ... }
Objective-C
[authResult.user.multiFactor getSessionWithCompletion:^(FIRMultiFactorSession * _Nullable session, NSError * _Nullable error) { // ... }];
Envie uma mensagem de validação para o telemóvel do utilizador. Certifique-se de que o número de telefone está formatado com um
+
inicial e sem outra pontuação ou espaço 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. }];
Embora não seja obrigatório, é uma prática recomendada informar os utilizadores antecipadamente de que vão receber uma mensagem SMS e que se aplicam as tarifas padrão.
O método
verifyPhoneNumber()
inicia o processo de validação de apps em segundo plano através de uma notificação push silenciosa. Se a notificação push silenciosa não estiver disponível,é emitido um desafio reCAPTCHA.Depois de o código SMS ser enviado, peça ao utilizador para validar o código. Em seguida, use a resposta 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. Opcionalmente, pode especificar um nome a apresentar para o segundo fator. Isto é útil para utilizadores com vários segundos fatores, uma vez que o número de telefone é ocultado 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! Registou com êxito um segundo fator de autenticação para um utilizador.
Iniciar sessão dos utilizadores com um segundo fator
Para iniciar sessão de um utilizador com a validação por SMS de dois fatores:
Inicie sessão no utilizador com o primeiro fator e, em seguida, detete um erro que indique que é necessária a autenticação multifator. Este erro contém um resolvedor, sugestões sobre os segundos fatores inscritos e uma sessão subjacente que prova que o utilizador efetuou a autenticação com êxito com o primeiro fator.
Por exemplo, se o primeiro fator do utilizador foi um email e uma palavra-passe:
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 utilizador for um fornecedor federado, como o OAuth, intercete o erro após chamar
getCredentialWith()
.Se o utilizador tiver vários fatores secundários inscritos, pergunte-lhe qual quer usar. Pode obter o número de telefone oculto com
resolver.hints[selectedIndex].phoneNumber
e o nome a apresentar 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. }
Envie uma mensagem de validação para o telemóvel do utilizador:
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. } }];
Assim que o código por SMS for enviado, peça ao utilizador para validar 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 início de sessão. Em seguida, pode aceder ao resultado do início de sessão original, que inclui os dados específicos do fornecedor padrão 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 início de sessão de um utilizador com autenticação multifator:
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! Iniciou sessão com êxito num utilizador através da autenticação multifator.
O que se segue?
- Faça a gestão de utilizadores com autenticação multifator de forma programática com o SDK de administrador.