Ответ
Да, реализовывал различные схемы аутентификации и авторизации в приложениях на Node.js.
1. JWT (JSON Web Tokens) для stateless-аутентификации.
Это наиболее частый выбор для RESTful API и микросервисов. Использую библиотеки jsonwebtoken для подписи/верификации и bcrypt для хэширования паролей.
const jwt = require('jsonwebtoken');
const bcrypt = require('bcrypt');
// Эндпоинт логина
app.post('/api/auth/login', async (req, res) => {
try {
const { email, password } = req.body;
const user = await UserModel.findOne({ email });
if (!user) {
return res.status(401).json({ error: 'Invalid credentials' });
}
const isPasswordValid = await bcrypt.compare(password, user.passwordHash);
if (!isPasswordValid) {
return res.status(401).json({ error: 'Invalid credentials' });
}
const token = jwt.sign(
{
userId: user.id,
role: user.role // Включаем роль для авторизации
},
process.env.JWT_SECRET,
{ expiresIn: '7d' }
);
res.json({ token, userId: user.id });
} catch (error) {
res.status(500).json({ error: 'Login failed' });
}
});
Защита роутов с помощью middleware:
const authMiddleware = (req, res, next) => {
const token = req.headers.authorization?.split(' ')[1]; // Bearer <token>
if (!token) return res.status(401).send('Access denied');
try {
const decoded = jwt.verify(token, process.env.JWT_SECRET);
req.user = decoded; // Добавляем данные пользователя в запрос
next();
} catch (err) {
res.status(400).send('Invalid token');
}
};
app.get('/api/profile', authMiddleware, (req, res) => {
res.json({ profile: '...', userId: req.user.userId });
});
2. Сессии (stateful).
Использовал express-session с хранилищем в Redis для традиционных веб-приложений, где нужны сессии.
3. OAuth 2.0 / OpenID Connect.
Интегрировал сторонние провайдеры (Google, GitHub) с помощью passport.js. Например, для аутентификации через Google:
const GoogleStrategy = require('passport-google-oauth20').Strategy;
passport.use(new GoogleStrategy({
clientID: process.env.GOOGLE_CLIENT_ID,
clientSecret: process.env.GOOGLE_CLIENT_SECRET,
callbackURL: '/api/auth/google/callback'
},
async (accessToken, refreshToken, profile, done) => {
// Находим или создаем пользователя в нашей БД на основе profile.id
const user = await findOrCreateUser(profile);
done(null, user);
}
));
4. Авторизация на основе ролей (RBAC). После аутентификации проверял права доступа. Часто создавал второй middleware для авторизации:
const authorize = (...allowedRoles) => {
return (req, res, next) => {
if (!req.user || !allowedRoles.includes(req.user.role)) {
return res.status(403).send('Forbidden');
}
next();
};
};
// Только админы могут удалять пользователей
app.delete('/api/users/:id', authMiddleware, authorize('admin'), deleteUserHandler);
Ключевые практики безопасности, которые я соблюдаю:
- Всегда храню пароли в виде хэшей (использую
bcryptс достаточным фактором стоимости). - Использую HTTPS в продакшене.
- Устанавливаю безопасные флаги для куков (HttpOnly, Secure, SameSite) при работе с сессиями.
- Регулярно обновляю секретные ключи (JWT_SECRET) и использую разные ключи для разных сред.
- Ограничиваю частоту попыток входа (rate limiting) для предотвращения брутфорса.