Tokens e Segurança
Introdução aos Tokens
Após implementar a autenticação básica, é fundamental garantir a segurança e a eficiência na gestão das sessões dos usuários. Para isso, utilizamos tokens, que são chaves de acesso que permitem aos usuários interagirem com a aplicação de maneira segura.
O que é um Token?
Um token é uma sequência de caracteres que atua como uma chave de acesso. Ele deve ser único, seguro e difícil de adivinhar, podendo ser gerado de forma aleatória ou por meio de algoritmos de hash. Os tokens são amplamente utilizados para:
Autorizar Acessos: Garantir que apenas usuários autenticados possam acessar certas rotas ou funcionalidades.
Manter Sessões: Manter o usuário autenticado durante a navegação na aplicação sem a necessidade de reautenticação constante.
Realizar Transações Seguras: Autorizar operações sensíveis, como transações financeiras.
Exemplos de Uso de Tokens
Aplicativos Bancários: Geram tokens para autorizar transações seguras.
Redes Sociais: Mantêm o usuário autenticado durante a navegação.
Autenticação em Duas Etapas (2FA): Geram códigos temporários para confirmar logins.
Carteirinha de Estudante: Utilizam tokens para acesso em universidades ou escolas.
JWT (JSON Web Token)
O JWT (JSON Web Token) é um padrão amplamente utilizado para a autenticação em serviços web. Ele permite o envio seguro de informações entre as partes como um objeto JSON, que pode ser verificado e confiável graças à sua assinatura digital.
Estrutura do JWT
Um JWT é composto por três partes, separadas por pontos (.
):
Header (Cabeçalho): Contém as informações sobre o tipo de token e o algoritmo de criptografia utilizado.
Payload (Carga): Contém as declarações (claims) que são os dados que você deseja transmitir, como informações do usuário.
Signature (Assinatura): Garante que o token não foi alterado. É gerada a partir do header, payload e uma chave secreta.
Exemplo de JWT:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
.
eyJ1c2VybmFtZSI6ImpvaG5kb2UiLCJpYXQiOjE2MTc5MjM5MDJ9
.
SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
Recursos Úteis
JWT.io Debugger: Ferramenta online para decodificar, verificar e depurar tokens JWT. Acessar JWT.io
Implementação do JWT
Vamos implementar a autenticação utilizando JWT no nosso projeto Node.js, garantindo que apenas usuários autenticados possam acessar rotas protegidas.
1. Instalação da Biblioteca jsonwebtoken
Primeiramente, instale a biblioteca jsonwebtoken
, que nos permitirá gerar e verificar tokens JWT.
npm install jsonwebtoken
2. Configuração das Chaves Secretas
Crie um arquivo de configuração para armazenar a chave secreta utilizada para assinar os tokens. Essa chave NUNCA DEVE estar exposta no código. Utilizaremos variáveis de ambiente para mantê-la segura.
Passos:
Instale a biblioteca dotenv para gerenciar variáveis de ambiente:
npm install dotenv
Crie um arquivo
.env
na raiz do projeto e adicione a chave secreta:SECRET_KEY=codelabMelhorGrupo
Atualize o arquivo
index.js
para carregar as variáveis de ambiente:// index.js require('dotenv').config(); const express = require('express'); const app = express(); const port = 3000; const produtosRouter = require('./routes/produtos'); const authRoutes = require('./routes/authRoutes'); app.use(express.json()); app.use('/produtos', produtosRouter); app.use('/auth', authRoutes); app.listen(port, () => { console.log(`Servidor rodando em http://localhost:${port}`); });
3. Geração e Validação de Tokens
Crie um serviço para gerenciar a geração e a validação dos tokens JWT.
// services/tokenService.js
const jwt = require('jsonwebtoken');
const SECRET_KEY = process.env.SECRET_KEY;
// Função para gerar token
exports.generateToken = (payload) => {
return jwt.sign(payload, SECRET_KEY, { expiresIn: '1h' });
};
// Função para verificar token
exports.verifyToken = (token) => {
return jwt.verify(token, SECRET_KEY);
};
4. Atualização do Service de Autenticação
Atualize o serviço de autenticação para utilizar o token JWT ao realizar o login.
// services/authService.js
const userRepository = require('../repositories/userRepository');
const hash = require('../utils/hash');
const tokenService = require('../services/tokenService');
exports.cadastrarUsuario = async (dados) => {
const { nome, email, telefone, cpf, senha } = dados;
// Verifica se o usuário já existe
const existeUsuario = await userRepository.findByEmail(email);
if (existeUsuario) {
throw new Error('Este email já está cadastrado');
}
// Gera o hash da senha
const senhaHash = hash.generate(senha);
// Cria o novo usuário
const novoUsuario = await userRepository.create({
nome,
email,
telefone,
cpf,
senha: senhaHash,
});
return novoUsuario;
};
exports.loginUsuario = async (dados) => {
const { email, senha } = dados;
// Busca o usuário pelo email
const usuario = await userRepository.findByEmail(email);
if (!usuario) {
throw new Error('Usuário/senha incorretos');
}
// Compara a senha fornecida com o hash armazenado
const senhaValida = hash.compare(senha, usuario.senha);
if (!senhaValida) {
throw new Error('Usuário/senha incorretos');
}
// Gera o token JWT
const tokenJWT = tokenService.generateToken({ id: usuario.id, email: usuario.email });
return tokenJWT;
};
5. Atualização do Controller de Autenticação
Atualize o controller para retornar o token JWT ao realizar o login.
// controllers/authController.js
const authService = require('../services/authService');
exports.cadastro = async (req, res) => {
try {
const usuario = await authService.cadastrarUsuario(req.body);
res.status(201).json(usuario);
} catch (error) {
res.status(400).json({ mensagem: error.message });
}
};
exports.login = async (req, res) => {
try {
const token = await authService.loginUsuario(req.body);
res.status(200).json({ token });
} catch (error) {
res.status(400).json({ mensagem: error.message });
}
};
6. Implementação do Middleware de Autenticação
Crie um middleware para proteger as rotas, verificando se a requisição possui um token válido.
// middleware/authenticate.js
const tokenService = require('../services/tokenService');
function authenticate(req, res, next) {
const authHeader = req.headers.authorization;
if (!authHeader) {
return res.status(403).json({ mensagem: 'Sem autorização' });
}
const token = authHeader.split(' ')[1];
if (!token) {
return res.status(403).json({ mensagem: 'Sem autorização' });
}
try {
const decoded = tokenService.verifyToken(token);
req.user = decoded; // Adiciona os dados do usuário à requisição
next();
} catch (err) {
return res.status(403).json({ mensagem: 'Token inválido' });
}
}
module.exports = authenticate;
7. Protegendo Rotas com Middleware
Utilize o middleware de autenticação para proteger rotas que requerem usuário autenticado.
// routes/produtos.js
const express = require('express');
const router = express.Router();
const prisma = require('../prismaClient');
const authenticate = require('../middleware/authenticate');
// Rota para obter todos os produtos (pública)
router.get('/', async (req, res) => {
try {
const produtos = await prisma.produto.findMany();
res.json(produtos);
} catch (error) {
console.error(error);
res.status(500).send('Erro no servidor');
}
});
// Rota para adicionar um novo produto (protegida)
router.post('/', authenticate, async (req, res) => {
const { nome, quantidade, preco } = req.body;
try {
const novoProduto = await prisma.produto.create({
data: {
nome,
quantidade,
preco,
},
});
res.json(novoProduto);
} catch (error) {
console.error(error);
res.status(500).send('Erro no servidor');
}
});
module.exports = router;
Fluxo de Autenticação com JWT
Cadastro de Usuário:
O usuário envia seus dados para o endpoint
/auth/cadastro
.A senha é criptografada utilizando bcrypt.
Os dados do usuário são armazenados no banco de dados sem gerar um token.
Login:
O usuário envia suas credenciais para o endpoint
/auth/login
.As credenciais são verificadas e, se válidas, um token JWT é gerado e retornado.
O token deve ser armazenado no cliente (por exemplo, no
localStorage
) e enviado nas requisições subsequentes nas headers para acessar rotas protegidas.
Exemplo Prático de Cadastro e Login
Cadastro de Usuário:
Endpoint:
POST /auth/cadastro
Corpo da Requisição:
{ "nome": "João Silva", "email": "joao.silva@example.com", "telefone": "11999999999", "cpf": "12345678901", "senha": "senhaSegura123" }
Resposta:
{ "id": 1, "nome": "João Silva", "email": "joao.silva@example.com", "telefone": "11999999999", "cpf": "12345678901" }
Login de Usuário:
Endpoint:
POST /auth/login
Corpo da Requisição:
{ "email": "joao.silva@example.com", "senha": "senhaSegura123" }
Resposta:
{ "token": "seu_jwt_token_aqui" }
Last updated
Was this helpful?