No desenvolvimento de aplicações Vue.js, a integração com um backend para autenticação usando JWT (JSON Web Tokens) é crucial. Vamos explorar como configurar o modelo de dados, endpoints de registro e login, middleware de verificação de token, e o frontend Vue para gerenciar tokens.
Modelo de Dados no MongoDB com Mongoose
O esquema de usuário inclui campos essenciais como nome de usuário, email, senha criptografada, avatar, identidade e timestamps.
const mongoose = require('mongoose');
const userSchema = new mongoose.Schema({
nomeUsuario: {
type: String,
required: true
},
email: {
type: String,
required: true,
unique: true
},
senha: {
type: String,
required: true
},
avatarUrl: {
type: String,
default: ''
},
tipoIdentidade: {
type: Number,
required: true
},
criadoEm: {
type: Date,
default: Date.now
},
atualizadoEm: {
type: Date,
default: Date.now
}
});
module.exports = mongoose.model('User', userSchema);
Endpoint de Registro com Criptografia de Senha
Para registrar um novo usuário, primeiro verificamos se o email já existe. A senha é criptografada usando uma função de hash com sal antes de salvar.
const crypto = require('crypto');
const UserModel = require('./caminho/para/modelo/user');
function hashSenha(senha) {
const salSeguro = '!@#$%^&*()';
const hash = crypto.createHash('sha256');
hash.update(senha + salSeguro);
return hash.digest('hex');
}
router.post('/registrar', async (ctx) => {
const { nomeUsuario, email, senha, avatar, identidade } = ctx.request.body;
try {
const usuarioExistente = await UserModel.findOne({ email });
if (usuarioExistente) {
ctx.status = 409;
ctx.body = { status: 'erro', mensagem: 'Email já cadastrado' };
return;
}
const senhaCriptografada = hashSenha(senha);
const novoUsuario = new UserModel({
nomeUsuario,
email,
senha: senhaCriptografada,
avatarUrl: avatar,
tipoIdentidade: identidade
});
const usuarioSalvo = await novoUsuario.save();
ctx.body = { status: 'sucesso', dados: usuarioSalvo };
} catch (erro) {
ctx.status = 500;
ctx.body = { status: 'erro', mensagem: 'Falha no registro' };
}
});
Endpoint de Login e Geração de Token JWT
No login, verificamos as credenciais e, se válidas, geramos um token JWT com informações do usuário e tempo de expiração.
const jwt = require('jsonwebtoken');
const configSecret = require('./caminho/para/config').jwtSecret;
router.post('/autenticar', async (ctx) => {
const { email, senha } = ctx.request.body;
const usuario = await UserModel.findOne({ email });
if (!usuario) {
ctx.status = 404;
ctx.body = { status: 'erro', mensagem: 'Usuário não encontrado' };
return;
}
const senhaFornecida = hashSenha(senha);
if (usuario.senha !== senhaFornecida) {
ctx.status = 401;
ctx.body = { status: 'erro', mensagem: 'Credenciais inválidas' };
return;
}
const payload = {
id: usuario._id,
nome: usuario.nomeUsuario,
email: usuario.email,
identidade: usuario.tipoIdentidade,
expiraEm: Date.now() + 3600 * 1000
};
const tokenGerado = jwt.sign(payload, configSecret, { expiresIn: '1h' });
const dadosUsuario = {
nomeUsuario: usuario.nomeUsuario,
email: usuario.email,
avatar: usuario.avatarUrl,
tipoIdentidade: usuario.tipoIdentidade
};
ctx.body = { status: 'sucesso', dados: { ...dadosUsuario, token: `Bearer ${tokenGerado}` } };
});
Middleware de Verificação de Token
Um middleware no backend valida o token JWT em requisições protegidas, verificando sua assinatura e expiração.
const jwt = require('jsonwebtoken');
const UserModel = require('./caminho/para/modelo/user');
const segredoJWT = require('./caminho/para/config').jwtSecret;
async function verificarToken(ctx, next) {
const rotaAtual = ctx.request.path;
if (rotaAtual === '/autenticar' || rotaAtual === '/registrar') {
await next();
return;
}
const cabecalhoAuth = ctx.request.headers.authorization;
if (!cabecalhoAuth || !cabecalhoAuth.startsWith('Bearer ')) {
ctx.status = 401;
ctx.body = { status: 'erro', mensagem: 'Token não fornecido' };
return;
}
const token = cabecalhoAuth.split(' ')[1];
try {
const decodificado = jwt.verify(token, segredoJWT);
const agora = Date.now();
if (agora > decodificado.expiraEm) {
ctx.status = 401;
ctx.body = { status: 'erro', mensagem: 'Token expirado' };
return;
}
const usuarioValido = await UserModel.findById(decodificado.id);
if (!usuarioValido) {
ctx.status = 401;
ctx.body = { status: 'erro', mensagem: 'Usuário não autorizado' };
return;
}
ctx.state.usuario = decodificado;
await next();
} catch (erro) {
ctx.status = 401;
ctx.body = { status: 'erro', mensagem: 'Token inválido' };
}
}
module.exports = verificarToken;
Integração no Frontend Vue.js
No Vue.js, após o login, armazenamos o token no localStorage e decodificamos as informações do usuário para uso no estado da aplicação.
import jwtDecode from 'jwt-decode';
methods: {
async efetuarLogin(email, senha) {
const resposta = await axios.post('/autenticar', { email, senha });
if (resposta.data.status === 'sucesso') {
const token = resposta.data.dados.token;
localStorage.setItem('jwtToken', token);
const informacoesUsuario = jwtDecode(token);
this.$store.commit('definirUsuario', informacoesUsuario);
this.$router.push('/painel');
}
},
logout() {
localStorage.removeItem('jwtToken');
this.$store.commit('limparUsuario');
this.$router.push('/login');
}
}
Guia de Rotas no Vue Router
Protegemos rotas no frontend verificando a existência do token no localStorage antes de navegar.
router.beforeEach((para, de, proximo) => {
const tokenExistente = localStorage.getItem('jwtToken');
const rotasPublicas = ['/login', '/registrar', '/home'];
if (rotasPublicas.includes(para.path)) {
proximo();
} else if (!tokenExistente) {
proximo({ path: '/login' });
} else {
proximo();
}
});
Interceptador de Requisições Axios
Configuramos o Axios para incluir automaticamente o token JWT no cabeçalho de autorização em todas as requisições.
axios.interceptors.request.use(
(configuracao) => {
const token = localStorage.getItem('jwtToken');
if (token) {
configuracao.headers.Authorization = token;
}
return configuracao;
},
(erro) => {
return Promise.reject(erro);
}
);