Skip to content

Instantly share code, notes, and snippets.

@igorlima
Created April 26, 2015 20:36
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save igorlima/f33832a11a997c15ea03 to your computer and use it in GitHub Desktop.
Save igorlima/f33832a11a997c15ea03 to your computer and use it in GitHub Desktop.

Antes de mostrar qualquer código, eu gostaria de falar sobre a minha motivação para este post. Recentemente, eu palestrei na conferência de desenvolvedores de Confoo em Montreal. Se você não esteve lá, saiba que é um turbilhão de novas tecnologias, teorias de complexidade de dados, habilidades pessoais, e informações práticas e sólidas para tecnólogos de todos os tipos e níveis. Eu tive o prazer de frequentar (e palestrar) nos últimos dois anos e eu sempre encontrei uma gama de informações e ótimas oportunidades de networking. Este ano foi a primeira vez que a StrongLoop esteve presente, mas tendo em consideração os contatos feitos com ambos os usuários de LoopBack e os novos potenciais parceiros como Riak e Nexmo, espero que estaremos de volta no próximo ano.

O que é o LoopBack? É um framework open source para construir rapidamente APIs em Node e conectá-las aos dados.

Com base nas conversas de corredores e na frequência das sessões sobre isso, eu posso seguramente te dizer que o que foi mais comentado foi APIs. Desde código de frameworks a autenticação e monitoramento, todo mundo está se movendo nessa direção. De fato, a popularidade da apresentação do nosso Al Tsang na Node Summit mostrou esse impulso dentro e fora da comunidade Node. E o Node foi bem construído para tal tarefa.

Quanto a autenticação?

LoopBack já possui autenticação e autorização. Há uma classe base User que você pode usá-la diretamente ou estendê-la para atender às suas necessidades. Cada modelo no LoopBack também pode ter uma série de regras de controle de acesso usando as funções de usuários já existentes. Eu não vou aprofundar sobre estes mecanismos, mas você pode ler mais a respeito no link acima. Em vez disso, quero focar em alguns pontos de uma das sessões em Confoo: “Guia para iniciantes em autenticação alternativa” de Chris Cornutt.

image

Você pode ver os slides da palestra dele em sua página no SpeakerDeck, mas vou lhe mostrar a versão TL;DR: há uma série de tipos de mecanismos de autenticação, e todos eles têm suas próprias nuances, benefícios e problemas. Esta sessão é apenas uma visão geral de muitos desses mecanismos, mas isso me fez pensar sobre a autenticação nativa do LoopBack e como um desenvolvedor pode fazer isso de forma mais segura usando algum tipo de processo com mais de uma etapa.

Então, sem mais delongas, vamos ver como estender o sistema de login de usuário do LoopBack para utilizar a autenticação de duas etapas com um código enviado via SMS baseado em tempo.

SMS baseado em tempo

Com certeza há muitos mecanismos aprimorados de autenticação, como demonstra a apresentação do Chris, mas precisamos nos focar em algo amplamente aplicável para aplicações web e que podemos construir em um post de blog! Com a abundância de APIs de SMS, enviar um código baseado no tempo deve ser simples. Por que baseado no tempo? Queremos que o usuário só consiga usar esse código, quando estiver logando, e que esse código seja inútil depois de uma certa quantidade de tempo (talvez uns 60 segundos?).

image

O processo básico de login vai mudar de um simples formulário de entrada de e-mail e senha para um processo de duas etapas e meia:

  1. o usuário solicita um código de autenticação de duas etapas…
  • O usuário entra com seu e-mail e senha, para serem validados.
  • O sistema envia um código único para o dispositivo móvel do usuário.
  1. o usuário deve então digitar o código para para concluir o processo de “login”.

Ok, você me convenceu… Como que eu implemento isso?

Primeiro, crie um novo projeto com o LoopBack (você vai precisar de instalar o StrongLoop controller: npm instalar strongloop -g):

~$ slc loopback

Siga as instruções para criar sua aplicação, em seguida, crie um novo modelo que estende a classe User – eu chamei o meu de “Employee”. Dentro desse novo modelo Employee vamos criar dois novos métodos remotos para nosso processo de autenticação de duas etapas e 'meia'. Eu vou pular direto para os métodos, mas você pode ler sobre como criá-los no link da última frase.

Aqui é a nossa função para solicitar um novo código de duas etapas, com limite de tempo. Observe que ele faz 3 coisas básicas: localiza o usuário, verifica a senha e envia um código. Eu deixei de lado um monte de tratamento de erro, mas você pode ver esses tratamentos no exemplo do repositório. Também vamos usar a biblioteca speakeasy para gerar nossos tokens, então vamos baixá-la primeiro (certifique-se de instalar essa biblioteca como uma dependência: npm install --save speakeasy).

var speakeasy = require(‘speakeasy’);
 
module.exports = function(Employee) {
  
  Employee.requestCode = function(credentials, fn) {
    this.findOne({where: { email: credentials.email }}, function(err, user) {
      user.hasPassword(credentials.password, function(err, isMatch) {
        if (isMatch) {
          // Note that you’ll want to change the secret to something a lot more secure!
          var code = speakeasy.totp({key: ‘APP_SECRET’ + credentials.email});
          console.log(‘Two factor code for  + credentials.email + :  + code);
          
          // [TODO] hook into your favorite SMS API and send your user their code!
          
          fn(null, now);
        } else {
          var err = new Error(‘Sorry, but that email and password do not match!);
          err.statusCode = 401;
          err.code = ‘LOGIN_FAILED’;
          return fn(err);
        }
      });
    });
  };
};

Uma vez que o usuário tenha enviado o código de verificação com limite de tempo é preciso de um 'endpoint' para submetê-lo e completar o processo de login. Tenha em mente que este código expira rapidamente (30 segundos é o padrão para “Speakeasy”), então nossa interface do usuário deve estar pronto para aceitar o código imediatamente (sem atrapalhar o usuário com várias páginas!).

No exemplo abaixo eu deixei novamente de lado um monte de auditorias para abreviar este post. Certifique-se de fazer auditoria em tudo!

Employee.loginWithCode = function(credentials, fn) {
  var err = new Error(‘Sorry, but that verification code does not work!’);
  err.statusCode = 401;
  err.code = ‘LOGIN_FAILED’;
  
  this.findOne({ where: { email: credentials.email } }, function(err, user) {
    // And don’t forget to match this secret to the one in requestCode()
    var code = speakeasy.totp({key: ‘APP_SECRET’ + credentials.email});
    
    if (code !== credentials.twofactor) {
      return fn(err);
    }
    
    // Everything looks good, so now we can create the access token, which 
    // is used for all future API calls to authenticate the user.
    user.createAccessToken(86400, function(err, token) {
      if (err) return fn(err);
      token.__data.user = user;
      fn(err, token);
    });
  });
};

Ótimo! Estamos quase terminando a autenticação no lado do servidor. Tudo o que precisamos fazer é deixar público esses dois novos métodos remotos, caso contrário você teria que estar logado para efetuar login. :)

Abra o arquivo gerado /common/models/employee.json e atualize o objeto “acls” para permitir o acesso de $everyone para ambos os métodos:

“acls”: [
  {
    “principalType”: “ROLE”,
    “principalId”: “$everyone”,
    “permission”: “ALLOW”,
    “property”: “requestCode”
  },
  {
    “principalType”: “ROLE”,
    “principalId”: “$everyone”,
    “permission”: “ALLOW”,
    “property”: “loginWithCode”
  }
]

E quanto a integração com o SMS?

Você deve ter notado que há um item [TODO] no método Employee.requestCode() para enviar o código via SMS para o usuário. Eu não incluí esse código porque exigirá de sua parte uma integração e configuração de conta. Dito isso, muitas das empresas de API de voz e SMS tem uma API REST muito simples. Na verdade, pode ser tão simples como o exemplo abaixo (caso esteja usando o Nexmo):

var http = require(‘https’);
https.get(
  ‘https://rest.nexmo.com' +
      /sms/json?api_key=[YOUR_KEY]&api_secret=[YOUR_SECRET] +
      &from=[YOUR_NUMBER]&to=[USER_MOBILE_#] +
      &text=Your+verification+code+is+ + code,
  function() {
    res.on(‘data’, function(data) {
      // all done! handle the data as you need to
    });
  }
).on(‘error’, function() {
    // handle errors somewhow
});

Notificações push

Apesar de está fora do escopo deste artigo, se o SMS não é seu forte e você já está desenvolvendo uma aplicação móvel nativa, você também pode enviar o código de duas etapas usando o componente de notificação push do LoopBack!

Praticamente é isso para o servidor! Agora você pode executar slc run e acessar a url http://localhost:3000//explorer para ver o seu novo modelo e os métodos remotos personalizados. No entanto, eles não são muito interessantes sem vê-los em ação. Então, vamos construir um front-end de leve para ver como tudo se encaixa.

StrongLoop API Explorer

Um formulário simples de login

Primeiro, você deve seguir as instruções aqui para adicionar uma configuração de middleware para servir os arquivos estáticos do diretório “/client”; e depois adicionar um novo arquivo HTML dentro desse mesmo diretório. Você pode pegar o arquivo do meu repositório de exemplo, mas aqui que está a parte importante do formulário:

exemplo de um formulario simples de login

Agora adicione uma tag <script> na parte inferior do código HTML para fazer as requisições para o servidor. Vamos usar chamadas Ajax simples e manipulação de DOM para atingir o nosso objetivo, mas não fique preso aos detalhes, a interface do usuário pode ter diversas variações. Este exemplo é mais para demonstrar como conectar o lado do cliente com o servidor!

Quando o usuário submeter o formulário, vamos verificar se o usuário ainda têm um código de verificação, se não vamos solicitar um. Uma vez que o usuário tenha um código vamos enviar a segunda chamada da API para completar o processo de login.

Observe que o código abaixo foi reduzido no intuito de abreviar! Você pode ver o código UI do JavaScript na íntegra no repositório de exemplo.

document
  .getElementById(‘login’)
  .addEventListener(‘submit’, function(e) {
    var code = e.target.querySelector([name=code]).value;
    if (code) {
      ajaxCall({
        url: /api/Employees/requestCode’,
        method: ‘POST’,
        data: { email: emailFromForm, password: passFromForm },
        headers: {‘Content-Type’: ‘application/json’ },
        success: function(data) {
          alert(‘Your code is has been sent by SMS!);
        }
      });
    
    } else {
      ajaxCall({
        url: /api/Employees/loginWithCode’,
        method: ‘POST’,
        data: { email: emailFromForm, twofactor: codeFromForm },
        headers: { ‘Content-Type’: ‘application/json’ },
        success: function(data) {
          
          alert(‘You have logged in!);
          
          // The access token will be in the data for use with future API calls!
          console.log(data.id);
        }
      });
    }
  });

Me mostre o app!

Você pode acessar o código completo da aplicação no Github, apenas clone o repositório (ou faça o download do código), execute npm install a partir de um console para instalar todas as dependências e, em seguida, execute slc run para iniciar a aplicação! Vá em frente e acesse a url http://localhost:3000/ para ver a aplicação em ação! Você vai querer ver a tela do console, uma vez que ainda não temos a integração com o SMS ativada, o código de verificação simplesmente vai ser impresso no console do servidor.

aplicação exemplo em execução

Não pode ser só isso, pode?!

É só isso mesmo! Com apenas um par de métodos remotos podemos transformar uma aplicação nova do LoopBack em um sistema seguro com autenticação de duas etapas. Claro que é importante saber qual é o melhor mecanismo de autenticação para sua aplicação e seus usuários. Além disso, você vai querer adicionar controles adequado de acesso em todos os seus métodos de sua API. Confira o tutorial na documentação do nosso site para obter mais informações de configuração!

Quer mais?

Se este post apenas aguçou o seu apetite em saber mais sobre o LoopBack, camadas de controle de acesso, autenticação, APIs ou até mesmo SMS usando o Node.js então me siga no Twitter (@jakerella)! Ou basta postar um comentário, que vamos manter a discussão sobre segurança fluindo!

StrongLoop Arc é uma interface gráfica para a Plataforma de API da StrongLoop, que também inclui o LoopBack, ela complementa as ferramentas de linha de comando slc para o desenvolvimento rápido de APIs e conexão aos dados. Arc também inclui ferramentas para a construção, criação de perfil e monitoramento de aplicações Node. É preciso apenas poucas etapas para iniciar uma nova aplicação!

StrongLoop Arc

Você também pode estar interessado em…

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment