Авторизация и аутентификация в Node.js: Полное руководство
В современной веб-разработке безопасность пользовательских данных — приоритет номер один. В этом руководстве мы разберём ключевые инструменты и библиотеки для реализации аутентификации (проверки подлинности пользователя) и авторизации (проверки прав доступа) в приложениях на Node.js. Вы узнаете, как настроить защиту маршрутов, хешировать пароли и работать с токенами доступа.
1. Основные понятия
- Аутентификация — процесс проверки, является ли пользователь тем, за кого себя выдаёт (обычно через логин и пароль).
- Авторизация — определение, какие ресурсы и действия доступны аутентифицированному пользователю.
- JWT (JSON Web Token) — компактный и самодостаточный способ передачи данных в виде JSON-объекта. Используется для создания токенов доступа.
- Сессии — традиционный метод хранения данных о пользователе на сервере (обычно с использованием
express-session).
2. Ключевые библиотеки для Node.js
2.1. bcrypt — хеширование паролей
Никогда не храните пароли в открытом виде. bcrypt — это библиотека для безопасного хеширования с использованием соли.
const bcrypt = require('bcrypt');
const saltRounds = 10;
// Хеширование пароля
async function hashPassword(password) {
const salt = await bcrypt.genSalt(saltRounds);
const hash = await bcrypt.hash(password, salt);
return hash;
}
// Проверка пароля
async function checkPassword(password, hash) {
const match = await bcrypt.compare(password, hash);
return match; // true или false
}
2.2. jsonwebtoken — работа с JWT
Библиотека jsonwebtoken позволяет создавать и проверять JWT-токены. Токены обычно состоят из заголовка, полезной нагрузки (payload) и подписи.
const jwt = require('jsonwebtoken');
const secretKey = 'ваш-секретный-ключ';
// Создание токена
function generateToken(userId, role) {
const payload = { userId, role };
const token = jwt.sign(payload, secretKey, { expiresIn: '1h' });
return token;
}
// Проверка токена (middleware)
function verifyToken(req, res, next) {
const authHeader = req.headers['authorization'];
const token = authHeader && authHeader.split(' ')[1]; // Bearer TOKEN
if (!token) return res.status(401).json({ error: 'Токен не предоставлен' });
jwt.verify(token, secretKey, (err, decoded) => {
if (err) return res.status(403).json({ error: 'Недействительный токен' });
req.user = decoded;
next();
});
}
2.3. Passport.js — универсальная аутентификация
Passport.js — это middleware для Express, поддерживающий более 500 стратегий (локальная, OAuth, JWT, Google, Facebook и др.). Пример локальной стратегии:
const passport = require('passport');
const LocalStrategy = require('passport-local').Strategy;
const User = require('./models/User');
passport.use(new LocalStrategy(
async (username, password, done) => {
try {
const user = await User.findOne({ username });
if (!user) return done(null, false, { message: 'Пользователь не найден' });
const isValid = await bcrypt.compare(password, user.password);
if (!isValid) return done(null, false, { message: 'Неверный пароль' });
return done(null, user);
} catch (err) {
return done(err);
}
}
));
// Сериализация и десериализация (для сессий)
passport.serializeUser((user, done) => done(null, user.id));
passport.deserializeUser(async (id, done) => {
const user = await User.findById(id);
done(null, user);
});
3. Полный пример: регистрация и вход
Соберём всё вместе в простом Express-приложении.
const express = require('express');
const session = require('express-session');
const passport = require('passport');
const bcrypt = require('bcrypt');
const User = require('./models/User'); // модель Mongoose
const app = express();
app.use(express.json());
app.use(session({ secret: 'секрет', resave: false, saveUninitialized: false }));
app.use(passport.initialize());
app.use(passport.session());
// Регистрация
app.post('/register', async (req, res) => {
try {
const { username, password } = req.body;
const hashedPassword = await bcrypt.hash(password, 10);
const user = new User({ username, password: hashedPassword });
await user.save();
res.status(201).json({ message: 'Пользователь создан' });
} catch (err) {
res.status(500).json({ error: err.message });
}
});
// Вход (лок