Авторизация и аутентификация в TypeScript: от теории к практике
При разработке современных веб-приложений на TypeScript безопасность данных пользователей является приоритетной задачей. Два ключевых процесса — аутентификация (подтверждение личности) и авторизация (проверка прав доступа) — образуют фундамент любой защищённой системы. В этом руководстве мы разберём полный цикл реализации аутентификации и авторизации на TypeScript с использованием популярных библиотек и лучших практик.
1. Основные понятия и отличия
- Аутентификация — процесс проверки, является ли пользователь тем, за кого себя выдаёт (логин + пароль, биометрия, OAuth).
- Авторизация — процесс определения, какие ресурсы и действия доступны аутентифицированному пользователю (роли, права доступа).
Например: пользователь ввёл верный пароль (аутентификация), но ему запрещено удалять чужие посты (авторизация).
2. Необходимые инструменты и библиотеки
Для реализации мы будем использовать:
bcrypt— для хеширования паролейjsonwebtoken(JWT) — для создания и проверки токеновexpress+@types/express— серверная частьzod— валидация входных данных
3. Регистрация пользователя (аутентификация)
При регистрации пароль никогда не хранится в открытом виде. Используем bcrypt для создания хеша:
import bcrypt from 'bcrypt';
import { z } from 'zod';
const registerSchema = z.object({
email: z.string().email(),
password: z.string().min(8)
});
async function registerUser(email: string, password: string) {
const validated = registerSchema.parse({ email, password });
const saltRounds = 10;
const hashedPassword = await bcrypt.hash(validated.password, saltRounds);
// Сохраняем email + hashedPassword в базу данных
// await db.user.create({ data: { email, password: hashedPassword } });
return { success: true };
}
4. Вход в систему и выдача JWT
После успешной проверки пароля генерируем access-токен:
import jwt from 'jsonwebtoken';
const JWT_SECRET = process.env.JWT_SECRET!; // обязательно в .env
async function loginUser(email: string, password: string) {
// 1. Найти пользователя в БД по email
// const user = await db.user.findUnique({ where: { email } });
// if (!user) throw new Error('User not found');
// 2. Сравнить пароль
const isMatch = await bcrypt.compare(password, user.password);
if (!isMatch) throw new Error('Invalid password');
// 3. Создать JWT
const token = jwt.sign(
{ userId: user.id, role: user.role },
JWT_SECRET,
{ expiresIn: '1h' }
);
return { token, user: { id: user.id, email: user.email } };
}
5. Middleware для проверки JWT (аутентификация)
Создаём middleware, который будет проверять токен на каждый защищённый запрос:
import { Request, Response, NextFunction } from 'express';
interface AuthRequest extends Request {
user?: { userId: string; role: string };
}
export function authMiddleware(req: AuthRequest, res: Response, next: NextFunction) {
const authHeader = req.headers.authorization;
if (!authHeader?.startsWith('Bearer ')) {
return res.status(401).json({ error: 'No token provided' });
}
const token = authHeader.split(' ')[1];
try {
const decoded = jwt.verify(token, JWT_SECRET) as { userId: string; role: string };
req.user = decoded;
next();
} catch (err) {
return res.status(403).json({ error: 'Invalid or expired token' });
}
}
6. Авторизация на основе ролей (RBAC)
Создаём middleware для проверки прав доступа:
type Role = 'admin' | 'user' | 'moderator';
export function authorize(...allowedRoles: Role[]) {
return (req: AuthRequest, res: Response, next: NextFunction) => {
if (!req.user) {
return res.status(401).json({ error: 'Not authenticated' });
}
if (!allowedRoles.includes(req.user.role as Role)) {
return res.status(403).json({ error: 'Insufficient permissions' });
}
next();
};
}
// Использование в роуте:
// router.delete('/users/:id', authMiddleware, authorize('admin'), deleteUserHandler);
7. Безопасное хранение секретов
Никогда не храните JWT_SECRET и другие ключи в коде. Используйте переменные окружения:
// .env
JWT_SECRET=your-very-strong-secret-key-here
JWT_EXPIRES_IN=1h Также в библиотеке
opentelemetry-go для Go: полное руководство с примерами
WebSocket библиотеки TypeScript: ws и Socket.IO – полное руководство
Elasticsearch клиент для TypeScript: @elastic/elasticsearch
Обработка изображений на Go: изменение размера и обрезка (resize, crop)