Autenticação em Node.js com Passport – Parte 2

Atualizado em 26/08/2018!

Este post é uma continuação do tutorial de como implantar um mecanismo de autenticação completo em Node.js usando o middleware Passport. No tutorial passado fizemos funcionar a autenticação através de uma tela de login e impedimos que usuários anônimos entrem na tela de chat.

Nesta segunda parte vamos criar a tela de cadastro de usuário (Sign Up) e a tela de recuperação de senha (Forget Password), além que aprenderemos a enviar emails em Node.js.

  1. Criando o cadastro de usuário
  2. Aprendendo a enviar emails
  3. Criando a recuperação de senha

Se quiser ver este mesmo tutorial em formato de video aula, confira o meu curso online de Node.js e MongoDB. Caso prefira apenas o texto mesmo, vamos lá!

#1 – Criando o cadastro de usuário

No tutorial anterior deixamos nosso banco preparado e a conexão compartilhada em uma variável global.db. Usaremos esta conexão global para fazer as operações de banco necessárias. Também usaremos o mesmo módulo bcrypt para criptografar as senhas no banco.

Para começar, vamos criar a nossa tela de cadastro de usuário que pedirá username, password e email, chamei ela de views/signup.ejs:

Note que este form faz um POST para uma rota /users/signup e que ele já espera uma message no model para exibir erro, caso dê algum problema. Faremos isso tudo funcionar depois.

Para que essa view possa ser exibida, primeiro vamos criar um novo arquivo de rotas em routes/users.js. Aqui colocaremos todas as rotas relacionadas a usuários, a começar pela rota que exibe a view que acabamos de criar via GET:

Note que já fiz o teste para passar ou não uma mensagem de falha para a tela no model, pra não dar erro na minha view. Agora para que essa rota passe a funcionar, temos de configurar nosso app.js, como abaixo:

Salve tudo e mande rodar sua aplicação para ver ela funcionando no navegador (use o link de “Não possui cadastro?” que deixamos prontos na tela de login):

Cadastro de Usuário
Cadastro de Usuário

Note que para acessar essa tela a rota é /users/signup. Isso porque definimos no app.js que rotas ‘/’ são tratadas pela index.js e rotas ‘/users’ são tratadas pela users.js, ou seja, há um roteamento inicial com ‘/users’ e depois o outro roteamento com ‘/signup’, virando ‘/users/signup’ a rota completa.

Agora, antes de sair programando a rota POST /users/signup que está em nosso HTML FORM, devemos criar a função JS que vai salvar um novo usuário no MongoDB. Para armazenar não apenas essa mas outras funções relacionadas a banco de dados (que não são de autenticação, pois estas deixamos no arquivo auth.js), vamos criar um arquivo db.js na raiz do nosso projeto. Dentro dele, vamos criar e expor uma função createUser, como abaixo:

Aqui eu pego a senha plain-text enviada pela view e gero o hash dela usando um salt de 10 rounds, que foi o que achei como sendo seguro atualmente, embora esta resposta dê um panorama mais completo de como calcular isso se seu sistema realmente precisar de uma segurança acima da média (bancos?). Ao final do processo, chamo uma função de callback que a createUser espera como último parâmetro.

Com esse módulo db.js pronto, programar essa rota de /users/signup será bem simples! Vá em routes/users.js e adicione uma rota POST para /signup, como abaixo (lembrando que o path /users já é tratado no app.js):

Aqui eu carrego o módulo ‘db’ que acabamos de criar e com ele chamo a função createUser, passando os dados enviados no corpo da requisição HTTP: username, password e email. Como último parâmetro, passo uma arrow function como callback, que apenas vai redirecionar para a tela de login em caso de sucesso e para a própria tela de signup em caso de fracasso, onde uma mensagem de erro será exibida.

Execute novamente sua aplicação e teste a criação de usuário. Se tudo deu certo, após a criação você poderá se autenticar na tela de login usando esse novo usuário.

Mas o que você acha de mandarmos um email de boas vindas para esse usuário que recém se cadastrou?

Curso Node.js e MongoDB
Curso Node.js e MongoDB

#2 – Aprendendo a enviar emails

Após o usuário se cadastrar, vamos enviar um email de boas vindas para ele. Além de ser algo interessante, fazer a lógica de envio de emails será útil na próxima etapa do tutorial, que é reset de senha por email.

Para fazer o envio de emails vamos usar um módulo chamado Nodemailer, que deve ser instalado via linha de comando usando o NPM:

Depois, vamos criar um módulo mail.js na raiz do nosso projeto, com o seguinte código:

Nosso módulo mail.js apenas expõe uma função que espera o destinatário da mensagem (to), o assunto (subject) e o texto (text). Por fim, a função sendMail faz o serviço propriamente dito.

Note que as configurações de SMTP para envio de email estão definidas em variáveis de ambiente, assim como fizemos na parte 1 deste tutorial para guardar a connection string do MongoDB.

Não esqueça que para que essas variáveis de ambiente funcionem, você deve adicionar o modelo delas no arquivo .env.example (é um arquivo oculto, você só vai conseguir ver ele com VS Code ou no terminal):

E com os valores finais no arquivo .env:

Aqui usei minha conta de email na Umbler para enviar os emails (você pode criar sua conta lá e ganhar créditos de graça para gastar com um email que custa centavos por mês). Como é uma aplicação de teste que vai enviar poucos emails, não vamos ter problemas. No entanto, caso queira usar o nodemailer para enviar muitos emails, você rapidamente será bloqueado em qualquer provedor de hospedagem. O certo é usar serviços de SMTP Gateway como Amazon SES, Mandrill e SendGrid.

Agora, para usarmos este módulo e finalmente fazer o envio de email de boas vindas funcionar, adicione apenas uma linha a mais em nossa rota POST em users.js:

Obviamente você pode personalizar essa mensagem livremente, ao invés do “email espartano” que deixei configurado. Soluções mais profissionais geralmente envolvem criar templates HTML que são lidos usando o módulo ‘fs’, algumas variáveis dentro do template são trocadas e depois a string resultante é enviada como HTML.

Rode novamente sua aplicação com ‘npm start’ e realize o cadastro de um novo usuário, mas informando um email válido, para que a mensagem chegue e você possa ver o resultado no seu webmail.

Email enviado via Node.js
Email enviado via Node.js

#3 – Criando a recuperação de senha

Agora a próxima parte é a de recuperação de senha. Lembra que deixamos um link pra isso lá na tela de login?

Vamos começar criando uma nova view, a views/forgot.ejs, com um formulário bem simples que pede a confirmação de seu email para envio de uma nova senha:

E para que essa tela seja acessível, vamos criar uma nova rota GET em routes/users.js:

Rodando sua aplicação e acessando no navegador, já deve ser possível navegar até esta página usando o link na tela de login:

Esqueceu a senha
Esqueceu a senha

Para fazer funcionar este formulário, vamos começar criando duas funções em nosso arquivo db.js: uma que busca um usuário pelo seu email e outra que muda a senha de um usuário:

A primeira função é bem simples, um findOne por email, que executa um callback após encontrar (ou não) o usuário. A segunda recebe uma senha, criptografa ela e sobrescreve o hash de senha do usuário cujo id foi passado por parâmetro. O module.exports no final do db.js também foi atualizado de acordo.

Note que não estou criando as devidas validações em nenhum formulário para os artigos não ficarem gigantescos. Nem de campos obrigatórios, nem validações de regras de negócio como não permitir usuários e emails duplicados. Tenha em mente que você deverá implementar essas questões se for usar esses códigos em produção.

Antes de sairmos fazendo a rota POST, vamos criar um arquivo utils.js na raiz do nosso projeto e colocar dentro dele uma função de geração de senha aleatória:

Esta função é bem simples e talvez você até queira usar alguma mais avançada. Aqui eu crio e retorno uma senha aleatória de 10 caracteres alfanuméricos (maiúsculas, minúsculas e números).

Agora que temos estas funções podemos criar a nossa rota POST que vai receber os dados do formulário de “esqueci minha senha”. Abra o arquivo routes/users.js e crie a nova rota:

Aqui começamos com o findUser que criamos anteriormente, que busca usuário por email. Caso não encontre, vamos jogar o usuário para a tela de login mesmo assim, embora você possa pensar em algo mais criativo para fazer.

Caso encontre, mandamos gerar uma nova senha usando a função que criei há pouco e uso o changePassword para mudar a senha do usuário que possui o email especificado (em um sistema de produção, para evitar problemas, além do email, peça alguma informação pessoal do usuário para confirmar esse processo de troca de senha). Por fim, um email é enviado com a senha que acabou de ser gerada, como na imagem abaixo.

Nova senha
Nova senha

Se você tentar se autenticar com a senha antiga, notará que ela não funciona mais, somente a nova.

É uma boa prática guardar o hash das últimas senhas do usuário e não deixar que ele use senhas antigas (mesmo senhas aleatórias podem conflitar ocasionalmente). Outra boa prática seria no primeiro login com a nova senha ele ser solicitado a cadastrar uma senha pessoal ao invés dessa aleatória. Enfim, sempre há margem para melhorar quando o assunto é segurança.

Não é exatamente uma parte 3, mas este tutorial sobre JSON Web Token ajuda a preencher a lacuna de autorização (visto que até o momento vimos apenas autenticação). No caso de estar utilizando arquitetura microservices, é uma boa colocar sua autenticação vinculada a regras de autorização no seu API Gateway.

Até a próxima!

Curtiu o post? Então clica no banner abaixo e dá uma conferida no meu livro sobre programação web com Node.js ou clique neste link para conhecer o meu curso online!

Como criar um aplicativo Android que envia emails

aplicacoes_email_android
Hoje vou ensinar como você pode enviar emails através de um app Android.

Diversos apps Android que desenvolvi para empresas como LG, Embelleze e Renault necessitavam que, após o usuário usar o app, que a interação fosse enviada por email para o próprio usuário e/ou para a empresa dona do app. Essa interação podia ser o preenchimento de um formulário, uma foto tirada com o app, as respostas de um quiz, etc.

Para exemplificar vamos criar uma tela que pede o nome e email de uma pessoa, e quando ela clicar em um botão no final do formulário, vamos enviar um email para ela. Se você nunca fez um app Android antes, recomendo a leitura deste ebook bem curtinho.

O layout XML da tela, chamada aqui de activity_main.xml, segue abaixo:

Isso deve gerar uma interface como abaixo:

Envio de Email
Envio de Email

Agora, na activity por trás dessa tela, chamada de MainActivity, temos de adicionar o código do evento de clique desse botão, que chama um método de envio de email.

O método enviarEmail chamado no clique do botão anterior deve ler os campos informados pelo usuário (nome e email), verificar se o smartphone está conectado na Internet (afinal, se não estiver vai dar erro no envio do email) e depois envia o dito cujo usando uma outra classe Java.

Note que me preocupei em realizar o envio do email em uma thread separada, como manda as guidelines do Android, evitando que a tela fique travada durante o envio, o que pode demorar alguns segundos dependendo da sua conexão com a Internet e do seu provedor de email.

Também incluí um comentário contendo o código para adicionar um anexo, que apenas precisa da URI de um arquivo armazenado no seu dispositivo.

A classe Mail utilizada no exemplo anterior foi encontrada na Internet há vários anos atrás e se mostrou bem confiável. Não lembro o quanto já customizei ela, mas de qualquer forma segue abaixo a versão mais atual que possuo, na íntegra (crie ela em outro arquivo de classe Java).

Aqui você deve prestar atenção no construtor vazio da classe Mail para colocar as configurações do seu servidor, como host SMTP, porta SMTP, se vai usar SSL, usuário e senha do seu email, etc.

Caso você nunca tenha enviado um email via software antes, é necessário que você se autentique em algum servidor de email com um usuário e senha válidos para poder enviar emails em seu nome. Ou seja, você vai ter de descobrir as configurações SMTP do seu provedor de email, além de saber o seu usuário (o próprio email) e senha (sua senha) para autenticação. São aquelas mesmas configurações usadas para o Outlook, sabe? Essas informações podem ser facilmente encontradas na Internet se seu email for Gmail, Hotmail, etc. Caso contrário consulte a empresa que lhe fornece emails (ex. Umbler) para obter as configurações de envio.

Para que essa classe funcione você vai precisar adicionar 3 bibliotecas Java ao seu projeto, que disponibilizo nesse zip. Basta descompactar e colocar os arquivos na pasta libs do seu projeto de app e pela IDE (normalmente o Android Studio) ir até a pasta libs e com o botão direito selecionar a opção ‘Add as library’ ou semelhante.

Add as Library
Add as Library

E para encerrar o que é necessário para que o código de envio de email funcione, falta criarmos o método isOnline() na MainActivity.java, responsável por testar a conexão com a Internet, pré-requisito para envio de email, conforme abaixo.

Como estamos mexendo com recursos de hardware como Internet, conexão, etc. precisamos pedir essas permissões em nosso AndroidManifest.xml como abaixo.

E se for usar anexos, não esqueça de adicionar também a permissão de leitura de arquivos.

Isso deve ser o suficiente para que você consiga enviar emails a partir desse app bem simples para o email informado no formulário a primeira tela. Esses códigos podem ser usados em apps maiores que fazem outras coisas e onde você apenas usará essa lógica para avisar alguém ou enviar uma mensagem. Daí a parte da criatividade eu deixo com você. 😉

Dica Avançada

Se seu app for utilizado por muitos usuários e/ou tiver um volume de envio de emails muito grande, procure usar soluções profissionais de SMTP Gateway como AWS SES, SendGrid e Mandrill. Jamais confie nos serviços de contas de email fornecido por provedores de hospedagem pois elas são configuradas para pequenos envios, jamais para envios em lote e rapidamente seu provedor irá bloquear a conta de email que seu app usa se enviar muitas mensagens por hora.

O SendGrid, líder neste segmento, inclusive tem um plano gratuito em que você pode enviar 100 mensagens por dia de graça.

* OBS: curtiu o post? Então dá uma olhada no meu livro de Android clicando no banner abaixo pra aprender a criar outros tantos apps incríveis!

Criando apps para empresas com Android

Lean Inception: concepção de produtos enxutos – Parte 2

No artigo anterior iniciei conceituando o que é a Lean Inception. Falamos um pouco da sua história e tratei de resumir as dinâmicas que envolvem os dois primeiros dias de trabalho de uma inception (ou três, se você considerar o trabalho prévio). Entendemos que o foco da inception é sair com um entendimento comum do que será o produto e quais serão os primeiros passos da sua construção, o seu MVP inicial, bem como o roadmap que se seguirá a partir dele.

Claro, até o término do segundo dia não é possível ter tanta clareza assim uma vez que o melhor ainda está por vir nos dias seguintes. E é desses dias que vou falar nesta segunda e última parte do artigo sobre Lean Inception!

Dia 3: Quarta-Feira

Assim como todos os dias da inception, começa-se com uma energização e em seguida faz-se uma restrospectiva dos dias anteriores, neste caso passando pela Visão do Produto, o que ele É-Não É-Faz-Não Faz, quem são as Personas que usarão o produto e quais as Features que descobrimos para ele.

E é com esse gancho das features que iniciamos o terceiro dia da Inception, fazendo um nivelamento das mesmas, também chamado de Revisão Técnica e de Negócio. Esse nivelamento é feito com todo o grupo em conjunto de uma maneira tão simples quanto levantar a mão com uma nota de 1 a 3 para cada uma das perguntas seguintes:

  • de 1 a 3, qual o nível de entendimento de negócio que temos sobre esta feature?
  • de 1 a 3, qual o nível de entendimento técnico que temos sobre esta feature?

Conforme as respostas são consolidadas para cada feature (incentive o debate quando existirem notas 1 e 3 para a mesma feature, semelhante ao que fazemos em um Planning Poker), coloque-as em uma matriz como abaixo.

Matriz de Entendimento
Matriz de Entendimento

Ou seja, se uma feature recebeu nota 1 para entendimento técnico e 3 para entendimento de negócio, ela vai ficar no canto superior esquerdo. Essa feature deve ser sinalizada com a cor vermelha, geralmente colando o post-it dela sobre um cartão com esta cor.

Note que se a feature ficar posicionada em algum dos quadrantes com um X, ela não será incluída no MVP, pois seu nível de certeza é baixíssimo. Demais features em posições vermelhas devem ser melhor discutidas, features nos quadrantes amarelos estão com nível razoável de certeza e features verdes estão prontas para serem desenvolvidas.

Após essa análise sobre uma feature, fazemos uma segunda análise, também em grupo, respondendo as seguintes perguntas:

  • de 1 a 3, qual o esforço necessário para desenvolver esta feature? Marque o consolidado no canto do cartão da feature usando os símbolos E, EE ou EEE para o esforço.
  • de 1 a 3, qual o retorno financeiro desta feature? Marque o consolidado no canto do cartão da feature usando o símbolos $, $$ e $$$ para a receita.
  • de 1 a 3, o quanto os usuários vão amar esta feature? Marque o consolidado no canto do cartão da feature usando corações (1 a 3).

Na imagem abaixo está um exemplo de feature “estimar preço” nivelada com grau amarelo de certeza, esforço médio e receita alta. Não tem o coração ainda pois essa foi uma adição mais recente do Caroli ao método.

Feature Nivelada
Feature Nivelada

Após fazer isso com todas as features descobertas no dia anterior, teremos um canvas de features (aquele com as Personas x Features, lembra?) com mais detalhes sobre cada uma delas.

Feature Canvas nivelado
Feature Canvas nivelado

Note que as discussões geradas por esse nivelamento produzem muito mais do que apenas cards coloridos e marcações, elas dão uma clareza muito maior do que pretende-se desenvolver para todos os membros do grupo e inclusive você pode incluir mais informações aos cards para uso posterior, oriundas dessas discussões.

Na parte da tarde, sim o dia ainda não acabou, é hora de falarmos de Jornadas dos Usuários. Aqui a dinâmica é mais simples: cada grupo pega uma persona (se sobrar tempo pode fazer para mais de uma) e trabalha em uma jornada dela, onde haja ponto de contato com o produto que será desenvolvido.

Um excelente framework para essa dinâmica é pegar uma folha A2 para cada jornada e traçar uma matriz com as colunas sendo: antes, durante e depois e com as linhas sendo: ação, ponto de contato, pensamento e humor. Na coluna Antes você vai colocar as ações, em ordem cronológica, que vão levar o usuário a ter contato com seu produto, ele se deparando com o problema ou necessidade o qual o levará até o produto. Vale qualquer coisa, até falar do café da manhã dele. Para cada ação, não esqueça de citar os pontos de contato com o produto, o que o usuário está pensando naquele momento e como está o humor dele.

Na coluna Durante, descreva as ações do usuário já usando o produto, não esquecendo dos pensamentos e sentimentos também. Já na coluna Depois, descreva as ações pós-uso do produto, do usuário aproveitando o benefício obtido, por exemplo.

Caso mais de algum grupo faça a mesma jornada, é importante que haja uma consolidação através do consenso entre eles. Podem existir várias jornadas por persona, mas que não descrevam a mesma situação de uso do produto. Ao término do dia, todos apresentam suas jornadas, registra-se tudo e enviam-se os materiais gerados por email.

Dia 4: Quinta-Feira

No quarto dia, após a energização e recapitulação dos dias anteriores, é hora de mapear as features às jornadas do usuário. Lembra que lá atrás mencionei que era uma boa colocar identificadores únicos nas features? Pois é, aqui isso vai ser bem útil.

Mudam-se os grupos para que cada grupo fique com uma jornada que não foi criada pelo próprio grupo. Para cada ação do usuário (principalmente na etapa Durante), verifica-se quais features seriam utilizadas naquela ação, anotando o código da feature em um post it e colando próximo ou sobre a ação.

Caso note-se que tem alguma feature faltando, já cria-se ela e faz-se o nivelamento da feature individualmente que nem foi feito no dia anterior, colocando-a à disposição dos demais grupos no canvas de features.

Caso note-se que alguma feature ficou sobrando, talvez seja o caso de despriorizá-la, pois nas principais jornadas do usuário ela não se mostrou presente.

Após todos os times terminarem de mapear o uso das features nas suas jornadas, apresenta-se o resultado para o grande grupo.

Na parte da tarde do mesmo dia é hora de fazermos o Sequenciador de Features. Considerando tudo que foi aprendido e co-criado até aqui, vamos usar o Sequenciador de Features para definir o escopo do nosso MVP e o que sobrar ficará para as releases seguintes, em um roadmap incremental de produto.

Você cria a dinâmica do sequenciador com um único cartaz dividido em linhas horizontais (com altura suficiente para um card de feature e largura para três), numeradas à esquerda, como mostra a imagem abaixo.

Sequenciador de Features
Sequenciador de Features

Os times vão debater e decidir quais features devem ser implementadas primeiro (i.e. serem colocadas primeiro no sequenciador) considerando as jornadas mais importantes, precedência de features, etc. O preenchimento do Sequenciador é um trabalho do grupo inteiro. No entanto, existem algumas regras que devem ser seguidas, criadas pelo Caroli após várias inceptions na prática:

  1. Cada linha pode conter no máximo 3 features;
  2. Cada linha não pode conter mais do que 1 feature vermelha;
  3. Cada linha deve conter uma feature verde;
  4. A soma do esforço das features de uma linha não pode ser superior a 5 Es;
  5. A soma da receita das features de uma linha não pode ser menor que 4 $s;

Cada regra tem uma razão de existir e é recomendado que sejam seguidas à risca para garantir releases que balanceiem a entrega de valor x o risco. Considerando a ordem de cima para baixo e da esquerda para direita, em algum momento você conseguirá definir o escopo do primeiro MVP e dos MVPs seguintes.

Caso nunca tenha feito uma estimativa de alto nível antes, você pode pegar uma das features cujo nível de entendimento de negócio e técnico seja muito alto e tentar estimar em quanto tempo ela seria desenvolvida (usando T-Shirt Sizing, por exemplo) usando o time que você possui hoje. Com base nela você consegue estimar as demais por comparação e sinalizar no Sequenciador onde terminam cada um dos MVPs, montando o roadmap incremental do produto.

Dia 5: Sexta-Feira

No último dia da inception enxuta, é hora de consolidar tudo o que foi aprendido ao longo da semana em um MVP Canvas (técnica mais recente do que a mostrada no livro Direto ao Ponto original), cujo template você encontra abaixo. Claro, não esqueça de enviar a todos por email os resultados do dia anterior, fazer uma energização no início do dia e uma recapitulação das dinâmicas anteriores.

MVP Canvas
MVP Canvas

Um único MVP Canvas será criado para cada release do roadmap criado a partir do Sequenciador de Features, de maneira colaborativa entre todo o grupo. Mas nem só de consolidação é formado o canvas, pois algumas áreas exigirão que o grupo raciocine sobre o construído, de forma a torná-lo “user centered” e que seja possível medir o seu sucesso para pivotar ou não, uma vez que dependendo do aprendizado obtido a partir da construção deste MVP, todo o restante do roadmap pode ser alterado (não caia na armadilha de seguir um roadmap de  MVPs à risca e às cegas). É só seguir a cartilha do Lean Startup, não tem erro!

Resumidamente, você preenche o MVP Canvas da seguinte forma:

  • MVP Vision: baseado na Product Vision criada no primeiro dia da inception, derive para uma visão específica desta release;
  • Outcome Statement: qual o foco de aprendizado deste MVP? O que estaremos validando com esta entrega? O que esperamos alcançar?
  • Metrics: como iremos medir o progresso/sucesso deste MVP? Que índice indicará sucesso ou falha?
  • Personas & Platforms: para quais personas este MVP será lançado? E para quais plataformas? Restrinja a uma ou duas personas/plataformas em cada resposta.
  • Journeys: quais jornadas das personas escolhidas serão atendidas por este MVP?
  • Features: quais features do Sequenciador entrarão neste MVP?
  • Cost & Schedule: qual o custo e prazo desta entrega?

Após a construção do MVP Canvas, na parte da tarde é feito o showcase para todos os stakeholders do projeto, além do próprio grupo que trabalhou duro para chegar neste resultado, não é mesmo?!

E depois?

Com o MVP Canvas em mãos e todo mundo alinhado com o que deve ser feito no primeiro MVP, é hora de colocar a mão na massa rodando o bom e velho Scrum: o Product Owner terá de incluir as features dos canvas no seu Product Backlog, refinando-as em User Stories os que devam entrar no primeiro MVP, para que na primeira Sprint Planning o Time de Desenvolvimento consiga quebrá-las em tarefas, estimá-las em pontos e iniciar o desenvolvimento do produto de fato.

Para se aprofundar no assunto, leia o livro do Caroli, abaixo. Para mais conteúdo sobre Métodos Ágeis de desenvolvimento de software, recomendo o meu livro Scrum e Métodos Ágeis: Um Guia Prático.