Autorização e Autenticação em TypeScript: guia completo
No desenvolvimento web moderno, a segurança da aplicação é um aspecto criticamente importante. TypeScript, como uma extensão do JavaScript, fornece ferramentas poderosas para criar sistemas de autorização e autenticação tipados e seguros. Neste artigo, abordaremos os conceitos-chave, bibliotecas populares e escreveremos exemplos práticos em TypeScript.
Conceitos básicos
Antes de ir para o código, é importante distinguir dois termos:
- Autenticação (Authentication) — verificação da identidade do usuário (quem é você?). Geralmente é feita através de login/senha, tokens ou biometria.
- Autorização (Authorization) — determinação dos direitos de acesso (o que você pode fazer?). Por exemplo, acesso ao painel administrativo apenas para o papel "admin".
Bibliotecas populares para TypeScript
No ecossistema TypeScript/Node.js, existem várias soluções testadas:
- Passport.js — a biblioteca mais popular para estratégias de autenticação (local, JWT, OAuth). Possui excelente suporte a TypeScript através dos tipos
@types/passport. - jsonwebtoken — trabalho com JWT (JSON Web Tokens). Totalmente tipada.
- bcrypt — hash de senhas. Usado em conjunto com outras bibliotecas.
- express-session — gerenciamento de sessões no servidor.
Exemplo 1: Autenticação básica com JWT
Vamos criar um sistema simples com tokens de acesso. Instale as dependências:
npm install express jsonwebtoken bcrypt @types/express @types/jsonwebtoken @types/bcryptCriaremos um servidor com registro e login:
import express, { Request, Response } from 'express';import jwt from 'jsonwebtoken';import bcrypt from 'bcrypt';
const app = express();app.use(express.json());
const SECRET_KEY = 'your-secret-key';const users: { username: string; passwordHash: string }[] = [];
// Registroapp.post('/register', async (req: Request, res: Response) => { const { username, password } = req.body; const passwordHash = await bcrypt.hash(password, 10); users.push({ username, passwordHash }); res.status(201).json({ message: 'User created' });});
// Loginapp.post('/login', async (req: Request, res: Response) => { const { username, password } = req.body; const user = users.find(u => u.username === username); if (!user) return res.status(401).json({ error: 'Invalid credentials' });
const isValid = await bcrypt.compare(password, user.passwordHash); if (!isValid) return res.status(401).json({ error: 'Invalid credentials' });
const token = jwt.sign({ username }, SECRET_KEY, { expiresIn: '1h' }); res.json({ token });});
// Rota protegidaapp.get('/protected', (req: Request, res: Response) => { const authHeader = req.headers.authorization; if (!authHeader) return res.status(401).json({ error: 'No token provided' });
const token = authHeader.split(' ')[1]; // Bearer token try { const decoded = jwt.verify(token, SECRET_KEY); res.json({ message: 'Access granted', user: decoded }); } catch { res.status(403).json({ error: 'Invalid token' }); }});
app.listen(3000, () => console.log('Server running on port 3000'));Exemplo 2: Middleware para autorização com papéis
Vamos adicionar um modelo de papéis. Criaremos um middleware tipado:
interface JwtPayload { username: string; role: 'user' | 'admin';}
// Middleware para verificar autenticaçãofunction authenticate(req: Request, res: Response, next: Function) { const token = req.headers.authorization?.split(' ')[1]; if (!token) return res.status(401).json({ error: 'Unauthorized' });
try { const decoded = jwt.verify(token, SECRET_KEY) as JwtPayload; (req as any).user =