Node.js

Autenticação JWT com GraphQL, Node.js e Couchbase NoSQL

Há alguns meses, quando comecei a aprender sobre o GraphQL, escrevi um tutorial anterior para usá-lo com o Couchbase e o Node.js. O tutorial se concentrou nos conceitos básicos, que incluíam a criação de objetos GraphQL e a consulta desses objetos no banco de dados NoSQL, Couchbase. Depois de algum tempo, escrevi um tutorial que oferecia uma visão geral de como fazer isso. forma alternativa para usar o GraphQL com o Node.js, mesmo que a camada de banco de dados não fosse a ênfase.

Ao usar ou criar uma API, geralmente há cenários em que você não quer que todos os dados sejam acessíveis a todos. Nesses cenários, você desejaria algum tipo de regulamentação por meio de autorização e tokens de API. Como em uma API RESTful, isso pode ser feito facilmente por meio de tokens da Web JSON (JWT).

Veremos como usar o JWT em um GraphQL para proteger determinadas partes dos dados, em vez de todos ou nenhum.

De agora em diante, é provavelmente uma boa ideia entender pelo menos um pouco como funcionam os tokens da Web JSON (JWT). Se quiser dar uma olhada em um guia rápido de introdução, confira meu tutorial intitulado, Autenticação JWT em uma API com tecnologia Node.js. O foco desse tutorial não é o GraphQL, mas ele ainda funciona como um bom ponto de partida.

O objetivo deste tutorial é criar uma API que use GraphQL. Poderemos criar contas, obter tokens e usar esses tokens para acessar partes protegidas da nossa API. As instruções de instalação e configuração do Couchbase não farão parte deste tutorial, mas nada de especial precisa ser feito para fins de compatibilidade.

Criação de um novo aplicativo Node.js com as dependências do projeto

Antes de passarmos para as partes mais pesadas e complexas do nosso projeto, vamos criar um novo projeto com todas as dependências e algum código padrão. Supondo que você já tenha o Node.js instalado e configurado, execute o seguinte em sua CLI:

Os comandos acima criarão um novo package.json e instale cada um dos nossos pacotes necessários. Esses pacotes incluem uma biblioteca GraphQL, bem como uma extensão GraphQL para o Express Framework. Também estamos incluindo uma maneira de fazer hash dos dados da nossa senha, criar JWT e armazenar tudo no Couchbase. Eu poderia ter feito isso com uma única linha? Sim, mas achei que seria mais fácil de ler se eu separasse tudo.

Com o projeto criado, vá em frente e crie um arquivo app.js que inclui o seguinte código:

Vamos chamar o código acima de código boilerplate. Basicamente, estamos apenas fazendo algumas configurações e nada realmente relevante para o nosso objetivo final. Estamos importando nossos pacotes baixados, estabelecendo uma conexão com o Couchbase, configurando o Express Framework, definindo três endpoints e servindo na porta 3000.

Certifique-se de usar suas próprias informações do Couchbase em vez das informações que usei. Além disso, para aumentar a segurança, altere a variável jwt-secret portanto, seus tokens são criptografados de forma menos previsível do que os meus.

Criação de pontos de extremidade da API de conta simples para login e registro

Você notará em nosso código padrão que temos um endpoint para registro e login. Há muitas maneiras de realizar o que estamos tentando fazer, provavelmente algumas melhores do que a minha solução. No entanto, achei que o que veremos a seguir é lógico e fácil de implementar, sem nos afastarmos muito de nossos objetivos.

Começando com o /registrar temos o seguinte:

Quando um usuário envia uma solicitação POST com nome de usuário e senha no corpo, primeiro criamos um novo UUID para ser usado como nossa chave de documento do Couchbase e, em seguida, fazemos o hash da senha usando o Bcrypt, como demonstrado anteriormente em um tutorial que escrevi.

Depois que um hash é criado, armazenamos os dados do perfil no Couchbase e os retornamos. Todo o objetivo por trás do /registrar é para nos fornecer alguns dados para autenticação. Para autenticar, usamos o parâmetro /login conforme mostrado abaixo:

No código acima, estamos criando uma consulta N1QL para encontrar um documento que contenha um nome de usuário que corresponda ao nome de usuário que foi passado com a solicitação. Estamos usando uma consulta parametrizada para evitar qualquer tipo de ataque de injeção de SQL.

Se um documento for encontrado, comparamos a senha com hash armazenada com a senha que foi passada com a solicitação. Se corresponder, podemos assinar o ID do usuário usando nosso segredo, o que nos dá um JWT para ser usado em solicitações futuras.

Alguns aspectos a serem observados em nossos dois pontos de extremidade:

  1. Não estamos fazendo nenhuma validação de dados. Este é um exemplo e estamos tentando manter as coisas simples.
  2. Não estamos definindo uma expiração em nosso JWT. Normalmente, você gostaria que ele expirasse em uma hora, mas este é apenas um exemplo simples.

Até o momento, não fizemos nada com o GraphQL. Apenas estabelecemos a base para criar usuários e obter tokens da Web JSON. Embora estejamos criando JWT, não estamos validando se eles são precisos até o momento.

Validação de JSON Web Tokens (JWT) com uma função da estrutura Express

Quando se trata de trabalhar com dados protegidos, ter um JWT não é suficiente. Queremos ter certeza de que o token é de fato válido, verificando a assinatura. Também precisamos de uma solução para transmitir o JWT.

O Express Framework tem um middleware para trabalhar com tokens da Web JSON, mas achei a documentação insuficiente. Em vez disso, pareceu-me mais fácil criar meu próprio método de validação. Veja o seguinte:

Então, o que estamos fazendo no código acima?

Como estamos usando app.useEm cada solicitação, essa função será chamada. Quando essa função é chamada, examinamos os cabeçalhos da solicitação atual e procuramos um cabeçalho de autorização. Se houver um cabeçalho de autorização, certificamo-nos de que é um token de portador e usamos o valor real do token em nossa verificação. O token real é o nosso JWT. Se o token for válido, poderemos adicionar o valor decodificado à solicitação, que se tornará acessível no próximo estágio da nossa solicitação. Se nenhum token estiver presente, não se preocupe, pois nada acontecerá. Nossa lógica só verifica nossos tokens se eles existirem porque nem todos os pontos de dados estarão protegidos.

Existem maneiras melhores de obter nosso token JWT em uma solicitação e validá-lo? Provavelmente, mas o código acima funcionou quando o testei e não foi muito complicado.

Desenvolvimento de uma API parcialmente protegida com GraphQL e JavaScript

Agora que temos a lógica do JWT implementada, podemos nos concentrar no desenvolvimento da nossa API. Tecnicamente, a /login e /registrar fazem parte da nossa API, mas o foco é o GraphQL.

Antes de nos preocuparmos com as consultas, vamos nos concentrar em nossos objetos GraphQL:

Lembre-se, se você viu meu tutorial anterior Couchbase com GraphQLSe você não tiver uma visão geral, os objetos acima provavelmente parecerão um pouco diferentes. Isso se deve ao fato de eu tê-los modelado de acordo com meu tutorial alternativo de GraphQL. Basicamente, temos dois objetos em que um é para os dados da conta e o outro é para os dados do curso. Talvez não seja o melhor exemplo, mas vamos fazer com que funcione.

Os dados do curso farão referência a uma conta para o autor do curso. Criaremos um método de resolução para as informações do autor, mas ainda não o faremos. Vamos primeiro criar uma consulta para os dados da conta separadamente:

Só faz sentido que, quando temos uma consulta como contaSe quisermos obter dados de uma conta específica, provavelmente será a nossa própria conta. Se estivermos consultando nossa própria conta, provavelmente deveremos ter um JWT válido.

Observe como estamos usando context.decodeToken no código acima. O código contexto nos permite obter dados da solicitação e, no nosso caso, os dados do token decodificado podem existir na solicitação. Se não existirem, provavelmente deveremos lançar um erro, pois um token válido é um requisito para essa consulta.

Se tivermos um token válido, poderemos criar uma consulta N1QL e usar o ID do usuário para consultar nossa conta e retorná-la.

Nada mal, certo?

Vamos expandir nossas consultas. Na seção campos vamos adicionar outra consulta, mas desta vez estaremos consultando os dados do curso, e os dados do curso não serão necessariamente protegidos.

No código acima, estamos fazendo uma consulta N1QL simples para todos os cursos armazenados no banco de dados. O problema aqui é que, para os dados do autor, estamos obtendo apenas a chave, não os dados da conta totalmente carregados, que são protegidos.

Na verdade, faremos algumas manipulações de dados no objeto GraphQL para Tipo de curso Em vez disso:

Observe que agora temos um resolver na função autor propriedade. Nessa função, verificamos se há um token válido e, se não o encontrarmos, retornamos um erro. Essa verificação e esse erro só ocorrem se a propriedade autor dados são solicitados. Se a consulta não solicitar autor podemos obter as outras informações sem um token, pois elas não estão protegidas.

Há outro problema aqui. Não só estamos verificando se um JWT válido está presente, mas também queremos que o JWT corresponda aos dados retornados na consulta N1QL. Isso significa que, se tivermos vários autores, somente os autores para os quais temos permissão serão bem-sucedidos. Mais uma vez, não é o melhor exemplo, mas prova nosso argumento.

Para limpar as pontas soltas, precisamos atualizar nosso /graphql ponto final:

Tudo o que fizemos foi adicionar nosso esquema que inclui nossas duas possíveis consultas.

Conclusão

Embora nosso exemplo fosse simples, ele nos permitiu demonstrar consultas e partes de dados protegidos com o GraphQL, Couchbasee tokens da Web JSON (JWT). Alguns aspectos essenciais a serem lembrados:

  1. Os dados da solicitação podem ser acessados no GraphQL contexto variável.
  2. Os tokens e as contas da Web JSON provavelmente devem ser criados por meio de pontos de extremidade separados, em vez de mutações do GraphQL.
  3. Você pode restringir as consultas e as propriedades de dados com o JWT. Não se trata de uma série de eventos do tipo tudo ou nada.

Se você quiser saber mais sobre o GraphQL, sugiro que dê uma olhada no meu artigo tutorial anterior sobre o assunto. Para saber mais sobre o Couchbase com Node.js, confira o Portal do desenvolvedor do Couchbase.

Compartilhe este artigo
Receba atualizações do blog do Couchbase em sua caixa de entrada
Esse campo é obrigatório.

Autor

Postado por Nic Raboy, defensor dos desenvolvedores, Couchbase

Nic Raboy é um defensor das modernas tecnologias de desenvolvimento móvel e da Web. Ele tem experiência em Java, JavaScript, Golang e uma variedade de estruturas, como Angular, NativeScript e Apache Cordova. Nic escreve sobre suas experiências de desenvolvimento relacionadas a tornar o desenvolvimento móvel e da Web mais fácil de entender.

Deixe um comentário

Pronto para começar a usar o Couchbase Capella?

Iniciar a construção

Confira nosso portal do desenvolvedor para explorar o NoSQL, procurar recursos e começar a usar os tutoriais.

Use o Capella gratuitamente

Comece a trabalhar com o Couchbase em apenas alguns cliques. O Capella DBaaS é a maneira mais fácil e rápida de começar.

Entre em contato

Deseja saber mais sobre as ofertas do Couchbase? Deixe-nos ajudar.