Adicione autenticação multifator ao seu aplicativo Flutter

Se você tiver atualizado para o Firebase Authentication com Identity Platform, poderá adicionar a autenticação multifator por SMS ao seu aplicativo Flutter.

A autenticação multifator (MFA) aumenta a segurança do seu aplicativo. Embora os invasores frequentemente comprometam senhas e contas sociais, interceptar uma mensagem de texto é mais difícil.

Antes de você começar

  1. Habilite pelo menos um provedor que ofereça suporte à autenticação multifator. Todos os provedores oferecem suporte a MFA, exceto autenticação por telefone, autenticação anônima e Apple Game Center.

  2. Certifique-se de que seu aplicativo esteja verificando os e-mails dos usuários. A MFA requer verificação de e-mail. Isso evita que atores mal-intencionados se registrem em um serviço com um e-mail que não sejam de sua propriedade e, em seguida, bloqueiem o proprietário real adicionando um segundo fator.

  3. Android : se você ainda não definiu o hash SHA-256 do seu aplicativo no console do Firebase , faça-o. Consulte Autenticando seu cliente para obter informações sobre como encontrar o hash SHA-256 do seu aplicativo.

  4. iOS : no Xcode, habilite notificações push para seu projeto e certifique-se de que sua chave de autenticação de APNs esteja configurada com Firebase Cloud Messaging (FCM) . Além disso, você deve ativar os modos de segundo plano para notificações remotas. Para ver uma explicação detalhada desta etapa, consulte a documentação do Firebase iOS Phone Auth .

  5. Web : verifique se você adicionou o domínio de seus aplicativos no console do Firebase , em Domínios de redirecionamento OAuth .

Habilitando a autenticação multifator

  1. Abra a página Autenticação > Método de login do console do Firebase.

  2. Na seção Avançado , habilite a autenticação multifator de SMS .

    Você também deve inserir os números de telefone com os quais testará seu aplicativo. Embora opcional, é altamente recomendável registrar números de telefone de teste para evitar limitações durante o desenvolvimento.

  3. Se você ainda não autorizou o domínio do seu aplicativo, adicione-o à lista de permissões na página Autenticação > Configurações do console do Firebase.

Escolhendo um padrão de inscrição

Você pode escolher se seu aplicativo requer autenticação multifator e como e quando inscrever seus usuários. Alguns padrões comuns incluem:

  • Inscreva o segundo fator do usuário como parte do registro. Use este método se seu aplicativo exigir autenticação multifator para todos os usuários.

  • Ofereça uma opção ignorável para inscrever um segundo fator durante o registro. Os aplicativos que desejam incentivar, mas não exigem, a autenticação multifator podem preferir essa abordagem.

  • Forneça a capacidade de adicionar um segundo fator na conta do usuário ou na página de gerenciamento de perfil, 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 sensíveis à segurança.

  • Exigir a adição incremental de um segundo fator quando o usuário desejar acessar recursos com maiores requisitos de segurança.

Inscrevendo um segundo fator

Para inscrever um novo fator secundário para um usuário:

  1. Autentique novamente o usuário.

  2. Peça ao usuário que insira seu número de telefone.

  3. Obtenha uma sessão multifatorial para o usuário:

    final multiFactorSession = await user.multiFactor.getSession();
  4. Verifique o número de telefone com uma sessão multifatorial e seus retornos de chamada:

    await FirebaseAuth.instance.verifyPhoneNumber(
      multiFactorSession
    : multiFactorSession,
      phoneNumber
    : phoneNumber,
      verificationCompleted
    : (_) {},
      verificationFailed
    : (_) {},
      codeSent
    : (String verificationId, int? resendToken) async {
       
    // The SMS verification code has been sent to the provided phone number.
       
    // ...
     
    },
      codeAutoRetrievalTimeout
    : (_) {},
    );
  5. Assim que o código SMS for enviado, peça ao usuário para verificar o código:

    final credential = PhoneAuthProvider.credential(
      verificationId
    : verificationId,
      smsCode
    : smsCode,
    );
  6. Conclua a inscrição:

    await user.multiFactor.enroll(
     
    PhoneMultiFactorGenerator.getAssertion(
        credential
    ,
     
    ),
    );

O código abaixo mostra um exemplo completo de inscrição de um segundo fator:

  final session = await user.multiFactor.getSession();
 
final auth = FirebaseAuth.instance;
  await auth
.verifyPhoneNumber(
    multiFactorSession
: session,
    phoneNumber
: phoneController.text,
    verificationCompleted
: (_) {},
    verificationFailed
: (_) {},
    codeSent
: (String verificationId, int? resendToken) async {
     
// See `firebase_auth` example app for a method of retrieving user's sms code:
     
// https://github.com/firebase/flutterfire/blob/master/packages/firebase_auth/firebase_auth/example/lib/auth.dart#L591
     
final smsCode = await getSmsCodeFromUser(context);

     
if (smsCode != null) {
       
// Create a PhoneAuthCredential with the code
       
final credential = PhoneAuthProvider.credential(
          verificationId
: verificationId,
          smsCode
: smsCode,
       
);

       
try {
          await user
.multiFactor.enroll(
           
PhoneMultiFactorGenerator.getAssertion(
              credential
,
           
),
         
);
       
} on FirebaseAuthException catch (e) {
         
print(e.message);
       
}
     
}
   
},
    codeAutoRetrievalTimeout
: (_) {},
 
);

Parabéns! Você registrou com êxito um segundo fator de autenticação para um usuário.

Conectando usuários com um segundo fator

Para fazer login em um usuário com verificação SMS de dois fatores:

  1. Faça login do usuário com seu primeiro fator e, em seguida, capture a exceção FirebaseAuthMultiFactorException . Este erro contém um resolvedor, que pode ser usado para obter os segundos fatores registrados do usuário. Ele também contém uma sessão subjacente que prova que o usuário foi autenticado com sucesso com seu primeiro fator.

    Por exemplo, se o primeiro fator do usuário for email e senha:

    try {
      await _auth
    .signInWithEmailAndPassword(
          email
    : emailController.text,
          password
    : passwordController.text,
     
    );
     
    // User is not enrolled with a second factor and is successfully
     
    // signed in.
     
    // ...
    } on FirebaseAuthMultiFactorException catch (e) {
     
    // The user is a multi-factor user. Second factor challenge is required
     
    final resolver = e.resolver
     
    // ...
    }
  2. Se o usuário tiver vários fatores secundários inscritos, pergunte qual deles usar:

    final session = e.resolver.session;

    final hint = e.resolver.hints[selectedHint];
  3. Envie uma mensagem de verificação para o telefone do usuário com a dica e a sessão multifatorial:

    await FirebaseAuth.instance.verifyPhoneNumber(
      multiFactorSession
    : session,
      multiFactorInfo
    : hint,
      verificationCompleted
    : (_) {},
      verificationFailed
    : (_) {},
      codeSent
    : (String verificationId, int? resendToken) async {
       
    // ...
     
    },
      codeAutoRetrievalTimeout
    : (_) {},
    );
  4. Chame resolver.resolveSignIn() para concluir a autenticação secundária:

    final smsCode = await getSmsCodeFromUser(context);
    if (smsCode != null) {
     
    // Create a PhoneAuthCredential with the code
     
    final credential = PhoneAuthProvider.credential(
        verificationId
    : verificationId,
        smsCode
    : smsCode,
     
    );

     
    try {
        await e
    .resolver.resolveSignIn(
         
    PhoneMultiFactorGenerator.getAssertion(credential)
       
    );
     
    } on FirebaseAuthException catch (e) {
       
    print(e.message);
     
    }
    }

O código abaixo mostra um exemplo completo de login de um usuário multifator:

try {
  await _auth
.signInWithEmailAndPassword(
    email
: emailController.text,
    password
: passwordController.text,
 
);
} on FirebaseAuthMultiFactorException catch (e) {
  setState
(() {
    error
= '${e.message}';
 
});
 
final firstHint = e.resolver.hints.first;
 
if (firstHint is! PhoneMultiFactorInfo) {
   
return;
 
}
  await
FirebaseAuth.instance.verifyPhoneNumber(
    multiFactorSession
: e.resolver.session,
    multiFactorInfo
: firstHint,
    verificationCompleted
: (_) {},
    verificationFailed
: (_) {},
    codeSent
: (String verificationId, int? resendToken) async {
     
// See `firebase_auth` example app for a method of retrieving user's sms code:
     
// https://github.com/firebase/flutterfire/blob/master/packages/firebase_auth/firebase_auth/example/lib/auth.dart#L591
     
final smsCode = await getSmsCodeFromUser(context);

     
if (smsCode != null) {
       
// Create a PhoneAuthCredential with the code
       
final credential = PhoneAuthProvider.credential(
          verificationId
: verificationId,
          smsCode
: smsCode,
       
);

       
try {
          await e
.resolver.resolveSignIn(
           
PhoneMultiFactorGenerator.getAssertion(
              credential
,
           
),
         
);
       
} on FirebaseAuthException catch (e) {
         
print(e.message);
       
}
     
}
   
},
    codeAutoRetrievalTimeout
: (_) {},
 
);
} catch (e) {
 
...
}

Parabéns! Você fez login com êxito em um usuário usando autenticação multifator.

Qual é o próximo