Para implementar autenticação e autorização, usaremos JSON Web Tokens (JWTs). JWTs são tokens que contêm informações sobre o usuário autenticado e podem ser usados para verificar a identidade do usuário sem precisar consultar o banco de dados a cada requisição.
1. Ajustes no Banco de Dados:
Adicione a coluna path
à tabela arquivos
(se ainda não estiver adicionada) e crie uma tabela para usuários:
ALTER TABLE arquivos ADD COLUMN path TEXT; -- Adiciona a coluna path
CREATE TABLE usuarios (
id SERIAL PRIMARY KEY,
username VARCHAR(255) UNIQUE NOT NULL,
password VARCHAR(255) NOT NULL -- Em produção, use hash seguro!
);
2. Dependências:
Instale as dependências necessárias:
npm install jsonwebtoken bcryptjs
jsonwebtoken
: Para gerar e verificar JWTs.
bcryptjs
: Para criptografar senhas (essencial para segurança em produção).
3. Código Backend Atualizado (index.js ou server.js):
import express from 'express';
import pg from 'pg';
import bodyParser from 'body-parser';
import cors from 'cors';
import multer from 'multer';
import { v4 as uuidv4 } from 'uuid';
import fs from 'fs';
import path from 'path';
import jwt from 'jsonwebtoken';
import bcrypt from 'bcryptjs';
// ... (Configurações de multer, pool, etc., como antes) ...
// Função para gerar JWT
const generateToken = (user) => {
return jwt.sign({ userId: user.id, username: user.username }, 'sua_chave_secreta', { expiresIn: '1h' }); // Substitua 'sua_chave_secreta' por uma chave forte e segura em produção
};
// Middleware para autenticação
const authenticateToken = (req, res, next) => {
const authHeader = req.headers['authorization'];
const token = authHeader && authHeader.split(' ')[1];
if (token == null) return res.sendStatus(401);
jwt.verify(token, 'sua_chave_secreta', (err, user) => {
if (err) return res.sendStatus(403);
req.user = user;
next();
});
};
// Rotas
app.post('/api/register', async (req, res) => {
try {
const { username, password } = req.body;
const hashedPassword = await bcrypt.hash(password, 10); // Hash da senha
const client = await pool.connect();
await client.query('INSERT INTO usuarios (username, password) VALUES ($1, $2)', [username, hashedPassword]);
client.release();
res.status(201).json({ message: 'Usuário registrado com sucesso!' });
} catch (error) {
handleError(error, res);
}
});
app.post('/api/login', async (req, res) => {
try {
const { username, password } = req.body;
const client = await pool.connect();
const result = await client.query('SELECT * FROM usuarios WHERE username = $1', [username]);
client.release();
if (result.rows.length === 0) return res.status(401).json({ message: 'Usuário não encontrado' });
const user = result.rows[0];
const passwordMatch = await bcrypt.compare(password, user.password);
if (!passwordMatch) return res.status(401).json({ message: 'Senha incorreta' });
const token = generateToken(user);
res.json({ token });
} catch (error) {
handleError(error, res);
}
});
// Rotas protegidas por autenticação (exemplo para upload)
app.post('/api/upload', authenticateToken, (req, res) => {
// ... (código de upload como antes, mas agora com autenticação) ...
});
app.get('/api/files', authenticateToken, async (req, res) => {
try {
const client = await pool.connect();
const result = await client.query('SELECT * FROM arquivos');
res.json(result.rows);
client.release();
} catch (error) {
handleError(error, res);
}
});
// ... (outras rotas) ...
app.listen(port, () => {
console.log(`Servidor rodando na porta ${port}`);
});
4. Frontend (Exemplo básico – você precisará implementar a interação com as novas rotas):
Este é um exemplo rudimentar de como você faria a autenticação no frontend usando fetch
:
// Login
fetch('/api/login', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ username: 'seu_usuario', password: 'sua_senha' })
})
.then(response => response.json())
.then(data => {
localStorage.setItem('token', data.token); // Salve o token no localStorage
// Redirecione para a página principal ou faça outra ação
})
.catch(error => console.error('Erro no login:', error));
// Upload de arquivo (com autenticação)
fetch('/api/upload', {
method: 'POST',
headers: {
'Authorization': `Bearer ${localStorage.getItem('token')}`, // Adicione o token no header
'Content-Type': 'multipart/form-data' // Para uploads de arquivos
},
body: formData // Seu FormData com o arquivo
})
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error('Erro no upload:', error));
Observações Críticas:
- Segurança: A “chave secreta” usada no JWT deve ser extremamente segura e armazenada em variáveis de ambiente em produção. Nunca a coloque diretamente no código.
- Hashing de Senhas: O
bcryptjs
está sendo usado para criptografar senhas, mas em um ambiente de produção, você deve considerar práticas de segurança mais avançadas, como a utilização de um sistema de autenticação mais robusto.
- Tratamento de Erros: O tratamento de erros precisa ser ainda mais robusto e detalhado, incluindo logs de erro mais informativos.
- Validação de Dados: É crucial adicionar validação de dados para prevenir injeção de SQL e outros ataques.
- CORS: Certifique-se de configurar corretamente o CORS para permitir requisições do seu frontend para o backend.
Este exemplo fornece uma base sólida para autenticação e autorização. Lembre-se de adaptá-lo às suas necessidades e adicionar mais camadas de segurança conforme necessário para um ambiente de produção. Considere também bibliotecas de autenticação mais robustas para aplicações em produção.