Alura > Cursos de Mobile > Cursos de Flutter > Conteúdos de Flutter > Primeiras aulas do curso Flutter com Firebase: autenticando usuários com Authentication

Flutter com Firebase: autenticando usuários com Authentication

Conhecendo o Firebase Auth - Apresentação

Olá! Meu nome é Ricarth Lima e serei seu instrutor em mais uma jornada no maravilhoso mundo do Flutter.

Se você ainda não me conhece, eu sou um homem com cabelo crespo, olhos castanhos, nariz e bocas largos. Uso uma barba volumosa, além de óculos de armação retangular escura. Estou de fone de ouvido e camisa azul escura da Alura. No fundo, uma parede lisa com iluminação degradê do azul ao rosa.

Agora que já nos conhecemos, muito boas-vindas ao curso de Flutter com Firebase Authentication. Vamos novamente utilizar uma ferramenta do Firebase para empoderar nossas aplicações com Flutter.

Para usar essa ferramenta, vamos dar continuidade ao projeto de lista de compras colaborativas que fizemos nos cursos de Firestore, o Listin.

Queremos dar esse empoderamento usando o Firebase Authentication e também que cada pessoa que acesse a aplicação com sua conta tenha a mesma experiência e mantenha seus dados, independente do dispositivo que esteja.

Por isso, vamos aprender:

No nosso projeto, o banco de dados será o Firebase Cloud Firestore, mas poderemos aplicar nossos aprendizados em qualquer banco.

Para conseguir aproveitar o curso da melhor forma possível, é importante que você tenha conhecimento dos materiais que vamos detalhar na atividade sobre pré-requisitos. Sugerimos que leia essa atividade com bastante atenção.

Outro aviso é que você pode usar a ferramenta do Discord da Alura, onde temos uma comunidade com milhares de pessoas que vão ter interesses parecidos com o seus. Recomendamos que você acesse o Discord para aprender por meio do compartilhamento e da comunicação.

Vamos começar o curso? Até lá!

Conhecendo o Firebase Auth - Importando o projeto

Agora que entendemos bem a plataforma e a ferramenta que vamos usar, vamos conhecer uma situação interessante.

Você está com seu projeto de Flutter funcional. Inclusive, funciona até com o banco de dados na nuvem, o Cloud Firestore. Só que, numa sexta-feira às 17h, sua liderança chega com uma nova demanda: colocar uma autenticação de pessoas usuárias no nosso aplicativo. Isto é, as pessoas usuárias precisam ter contas e cada conta deve ter acesso ao banco de dados.

Mas, calma! Outra equipe de Flutter já desenvolveu a tela para você. O que você precisa fazer é só colocar esse comportamento de autenticação.

No ponto sobre o código do projeto, existem 2 formas que você pode escolher seguir:

  1. Se você vem da formação Flutter com Firebase, te recomendamos baixar e extrair o arquivo Authentication.zip. Depois, coloque-o na sua pasta Lib.
  2. Mas, se você está fazendo esse curso como primeiro curso da formação, você pode baixar o projeto completo.

Conhecendo a tela

Agora que estamos todos no mesmo ponto, podemos conferir a tela em Flutter criada pela equipe de apoio. Basta fazer a integração com o Firebase Authentication para dar o comportamento de gerenciamento de contas.

Celular com tela de autenticação da aplicação Listin em primeiro estado. Sob fundo verde, um retângulo branco com as informações de login. No topo do retângulo, logo do Listin e a mensagem "Bem-vindo ao Listin!". Logo abaixo, a mensagem "faça login para criar sua lista de compras" seguida dos campos de e-mail e senha. Na parte inferior do retângulo, um botão marrom "Entrar" e um link "Ainda não tem conta? Clique aqui para cadastrar."

Temos a logo do Listin, uma mensagem amigável e dois campos, um para e-mail e outro para senha. Logo abaixo, um botão para entrar. Como essas páginas seguem um padrão, imaginamos que a pessoa coloca o e-mail e a senha e depois clica no botão "Entrar" para acessar a conta.

Caso ela ainda não tenha uma conta, ela clica no link "Ainda não tem uma conta? Clique aqui para cadastrar". Com isso, a própria tela se adapta para receber as informações de cadastro.

Celular com tela de autenticação da aplicação Listin em segundo estado. Sob fundo verde, um retângulo branco com as informações de cadastro. No topo do retângulo, logo do Listin e a mensagem "Vamos começar?". Logo abaixo, a mensagem "faça seu cadastro para começar a criar sua lista de compras com Listin seguida dos campos de e-mail, senha, confirmação de senha e nome. Na parte inferior do retângulo, um botão marrom "Cadastrar" e um link "Já tem uma conta? Clique aqui para entrar."

É esse o sistema que vamos seguir e essa tela que vamos usar em quase todo o curso. A tela tem um primeiro estado de entrada com e-mail e senha e um segundo estado onde pedimos e-mail, senha, confirmação da senha e nome para fazer o cadastro da pessoa usuária.

Conhecendo o código

Vamos conferir como está organizado o nosso código no VSCode. Primeiro, dentro da pasta "lib", podemos verificar a estrutura da pasta "authentication": ela tem uma pasta "screens" que contém um arquivo auth_screen.dart. Pronto.

Podemos fechar nosso explorador ao clicar no ícone de duas folhas no canto superior direito.

Em auth_screen.dart, vamos ter um stateful widget chamado AuthScreen. Esse widget é chamado lá na main para visualizar a tela.

A classe _AuthScreenState que herda de AuthScreen começa com quatro controllers de TextFormField. Como já aprendemos, você já sabe o que esses controladores vão fazer: se conectar em nossos campos de textos.

Um detalhe que queríamos chamar a atenção está na linha 17: a variável do tipo booleano isEntrando que é igual a true. Esse trecho sinaliza que nesse momento inicial, a tela está no comportamento de login, ou seja, entrando.

Mas para baixo do código, vamos conferir que podemos alterar esse comportamento para mudar a tela.

auth_screen.dart:

import 'package:flutter/material.dart';
import 'package:flutter_firebase_firestore_second/_core/my_colors.dart';

class AuthScreen extends StatefulWidget {
  const AuthScreen({super.key});

  @override
  State<AuthScreen> createState() => _AuthScreenState();
}

class _AuthScreenState extends State<AuthScreen> {
  final TextEditingController _emailController = TextEditingController();
  final TextEditingController _senhaController = TextEditingController();
  final TextEditingController _confirmaController = TextEditingController();
  final TextEditingController _nomeController = TextEditingController();

  bool isEntrando = true;

  final _formKey = GlobalKey<FormState>();

// código omitido…

}

Depois, temos a classe Scaffold() que tem como filho questões como padding e scrollagem. Além disso, temos um Form com uma coluna e usamos a chave formKey para fazer a validação mais adiante.

Também temos uma imagem que vem de um repositório, por isso, não é preciso de preocupar com importação.

Em seguida, temos as mudanças que vão acontecer. Por exemplo, no texto de título, usamos um operador ternário para verificar se estamos entrando ou não. Se estamos entrando, aparece "Bem-vindo ao Listin!". Se estamos nos cadastrando, aparece "Vamos começar?". Essa estrutura se repete várias vezes no código, como na mensagem complementar.

E-mail e senha são situações que não vão mudar, por isso, sempre vão aparecer os TextFormField de e-mail e senha. Ambos construídos com validadores para verificar se o campo está vazio e se tem a quantidade suficiente de caracteres. No caso do e-mail, também verifica se tem o símbolo arroba e um ponto. A senha já está com obscureText para escurecer o texto e ficar com pontinhos no lugar dos caracteres.

Se entramos no emulador da aplicação, podemos testar a tela de login ao escrever "Rica" no campo de e-mail, deixar o campo senha vazio e clicar no botão "Entrar". Com isso, aparecem as mensagens de validação:

O valor do e-mail deve ser válido

Insira uma senha válida

Essa verificação está toda pré-configurada.

Depois, temos um Visibility() controlando uma coluna que mostra tanto o campo de confirmação de senha quanto o campo de nome, porque são campos que só aparecem quando nos cadastramos.

Por fim, temos um botão que muda o seu texto a depender da situação, para "Entrar" ou "Cadastrar". E a propriedade onPressed() do botão leva para um método chamado botaoEnviarClicado().

// código omitido…

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Padding(
        padding: const EdgeInsets.symmetric(
          vertical: 64,
          horizontal: 32,
        ),
        child: Center(
          child: SingleChildScrollView(
            child: Container(
              decoration: BoxDecoration(
                color: Colors.white,
                borderRadius: BorderRadius.circular(24),
              ),
              padding: const EdgeInsets.all(32),
              child: Form(
                key: _formKey,
                child: Column(
                  mainAxisAlignment: MainAxisAlignment.center,
                  crossAxisAlignment: CrossAxisAlignment.stretch,
                  children: [
                    Image.network(
                      "https://github.com/ricarthlima/listin_assetws/raw/main/logo-icon.png",
                      height: 64,
                    ),
                    Padding(
                      padding: const EdgeInsets.all(8.0),
                      child: Text(
                        (isEntrando)
                            ? "Bem vindo ao Listin!"
                            : "Vamos começar?",
                        textAlign: TextAlign.center,
                        style: const TextStyle(
                          fontSize: 24,
                          fontWeight: FontWeight.bold,
                        ),
                      ),
                    ),
                    Text(
                      (isEntrando)
                          ? "Faça login para criar sua lista de compras."
                          : "Faça seu cadastro para começar a criar sua lista de compras com Listin.",
                      textAlign: TextAlign.center,
                    ),
                    TextFormField(
                      controller: _emailController,
                      decoration: const InputDecoration(label: Text("E-mail")),
                      validator: (value) {
                        if (value == null || value == "") {
                          return "O valor de e-mail deve ser preenchido";
                        }
                        if (!value.contains("@") ||
                            !value.contains(".") ||
                            value.length < 4) {
                          return "O valor do e-mail deve ser válido";
                        }
                        return null;
                      },
                    ),
                    TextFormField(
                      controller: _senhaController,
                      obscureText: true,
                      decoration: const InputDecoration(label: Text("Senha")),
                      validator: (value) {
                        if (value == null || value.length < 4) {
                          return "Insira uma senha válida.";
                        }
                        return null;
                      },
                    ),
                    Visibility(
                        visible: !isEntrando,
                        child: Column(
                          children: [
                            TextFormField(
                              controller: _confirmaController,
                              obscureText: true,
                              decoration: const InputDecoration(
                                label: Text("Confirme a senha"),
                              ),
                              validator: (value) {
                                if (value == null || value.length < 4) {
                                  return "Insira uma confirmação de senha válida.";
                                }
                                if (value != _senhaController.text) {
                                  return "As senhas devem ser iguais.";
                                }
                                return null;
                              },
                            ),
                            TextFormField(
                              controller: _nomeController,
                              decoration: const InputDecoration(
                                label: Text("Nome"),
                              ),
                              validator: (value) {
                                if (value == null || value.length < 3) {
                                  return "Insira um nome maior.";
                                }
                                return null;
                              },
                            ),
                          ],
                        )),
                    const SizedBox(height: 16),
                    ElevatedButton(
                      onPressed: () {
                        botaoEnviarClicado();
                      },
                      child: Text(
                        (isEntrando) ? "Entrar" : "Cadastrar",
                      ),
                    ),
                    TextButton(
                      onPressed: () {
                        setState(() {
                          isEntrando = !isEntrando;
                        });
                      },
                      child: Text(
                        (isEntrando)
                            ? "Ainda não tem conta?\nClique aqui para cadastrar."
                            : "Já tem uma conta?\nClique aqui para entrar",
                        textAlign: TextAlign.center,
                        style: const TextStyle(
                          color: MyColors.blue,
                          fontWeight: FontWeight.bold,
                        ),
                      ),
                    )
                  ],
                ),
              ),
            ),
          ),
        ),
      ),
    );
  }

// código omitido…

Ao rolar mais para baixo do código, vamos entender o que esse método botaoEnviarClicado() faz. Esse método pega o e-mail, senha e nome para validar.

Mas, porque não pegamos a confirmação de senha também? Na verdade, a confirmação de senha já tem um próprio validador para conferir se a confirmação é igual a senha.

Na linha 169, fazemos a validação de e-mail, senha e nome. Caso esteja tudo certo, vamos verificar uma última vez a variável isEntrando.

Se a pessoa usuária está de fato entrando, vamos chamar o método _entrarUsuario(), passando como string o e-mail e a senha. Se estiver criando uma conta, vamos chamar o método _criarUsuario(), também passando e-mail, senha e nome.

Nosso papel é dar comportamento para os métodos _entrarUsuario() e _criarUsuario().

// código omitido…

  botaoEnviarClicado() {
    String email = _emailController.text;
    String senha = _senhaController.text;
    String nome = _nomeController.text;

    if (_formKey.currentState!.validate()) {
      if (isEntrando) {
        _entrarUsuario(email: email, senha: senha);
      } else {
        _criarUsuario(email: email, senha: senha, nome: nome);
      }
    }
  }

  _entrarUsuario({required String email, required String senha}) {
    print("Entrar usuário $email, $senha");
  }

  _criarUsuario(
      {required String email, required String senha, required String nome}) {
    print("Criar usuário $email, $senha, $nome");
  }
}

Nesse vídeo, entendemos como funciona a tela que recebemos para dar comportamento. A seguir, vamos fazer algumas configurações no FireBase Authentication. Até lá!

Conhecendo o Firebase Auth - Ativando o Firebase Auth

Já entendemos o código da nossa tela e conhecemos qual tela devemos dar comportamento. Qual o próximo passo?

O nosso desafio é fazer um sistema de gerenciamento de contas de pessoas usuárias. Para isso, dentro dessa caixa de ferramentas que é o Firebase, existe uma ferramenta que ajuda a fazer isso de forma online (na nuvem) e de uma forma mais tranquila do que seria desenvolver um back-end.

Por isso, estamos com a tela do Firebase aberta para fazer a configuração dessa ferramenta chamada Firebase Authentication.

Configuração do Firebase Auth

Para configurar essa ferramenta, vamos na barra lateral esquerda do dashboard do projeto flutter-firestore-first no Firebase. Clicamos em "Criação > Authentication".

Caso você venha da formação Flutter, esse é o mesmo projeto que usamos desde o primeiro curso do Firestore. Note como as ferramentas do Firebase se conectam muito bem.

Se você nunca configurou a autenticação nesse projeto, aparece uma tela de "authentication" roxa com o botão "Vamos começar" - similar a todas as ferramentas do Firebase. Logo abaixo, temos as informações que você precisa saber antes de usar a ferramenta.

No nosso caso, vamos clicar em "Vamos começar". Após carregar, vamos ser enviados para a tela de configuração.

Na aba "sign-in method" (método de login), já podemos entender quão poderoso é o Firebase Auth. Nele, temos a opção de provedores nativos de autenticação: como e-mail e senha, número do telefone, ou autenticação anônima por meio de um link. Também temos a opção da conexão com outros provedores, como Google, Facebook, Play Store, Microsoft, Twitter, GitHub, entre outros.

Para esse curso, vamos usar o provedor nativo usando e-mail e senha, pois supre muitas das nossas necessidades, além de ser a opção de mais fácil configuração.

Quando lidamos com outros provedores, precisamos fazer configurações também nesse provedor terceiro. Por exemplo, lá na Google ou no Facebook. Enquanto com e-mail e senha, só usamos o Firebase.

Após escolher a opção de e-mail e senha, vamos clicar para ativar o interruptor ao lado direito de "e-mail/senha". Não precisamos ativar o "link do e-mail (login sem senha)". Em seguida, apertamos no botão "Salvar".

Nosso authentication já funciona e está habilitado para que projetos Flutter (e outros projetos de outras plataformas) conectados ao projeto flutter-firestore-first consiga fazer a autenticação por meio de e-mail e senha.

Fique à vontade para explorar esse dashboard na parte de Authentication, pois tem várias outras opções. Por exemplo, na aba "Users" (usuário), conseguimos conferir os identificadores das pessoas cadastradas, apesar de não visualizar dados sensíveis.

Na aba "Templates" (modelos), conseguimos mudar os e-mails que vão chegar ao fazer a verificação de endereço de e-mail, redefinição de senha, alteração de endereço de e-mail, entre outros.

Na aba "Usage" (uso), podemos conferir o nosso uso. É uma parte importante caso queira escalar o projeto, pois a quantidade uso deve caber no orçamento.

Por fim, temos configurações mais avançadas na aba "Settings" (configurações) para você explorar, caso necessário.

Agora que configuramos o Firebase Authentication no dashboard do Firebase, chegou a hora de fazer a configuração no nosso projeto Flutter. Até lá.

Sobre o curso Flutter com Firebase: autenticando usuários com Authentication

O curso Flutter com Firebase: autenticando usuários com Authentication possui 200 minutos de vídeos, em um total de 55 atividades. Gostou? Conheça nossos outros cursos de Flutter em Mobile, ou leia nossos artigos de Mobile.

Matricule-se e comece a estudar com a gente hoje! Conheça outros tópicos abordados durante o curso:

Aprenda Flutter acessando integralmente esse e outros cursos, comece hoje!

Conheça os Planos para Empresas