Стратегия local в Passport.js используется для
аутентификации пользователей на основе логина и пароля, передаваемых
непосредственно в приложение. В отличие от OAuth-стратегий, здесь вся
ответственность за хранение, проверку и безопасность паролей лежит на
серверной части.
Ключевой аспект такой схемы — корректная работа с паролями через
хэширование. Прямое хранение паролей недопустимо, поэтому используется
библиотека password-hash или аналогичные решения
(bcrypt, argon2). Основная идея — хранить не
сам пароль, а его криптографический отпечаток.
Local-стратегия строится вокруг проверки двух значений:
При попытке входа Passport вызывает функцию проверки, где происходит:
Пример логики:
passport.use(new LocalStrategy(
function(username, password, done) {
User.findOne({ username: username }, function (err, user) {
if (err) return done(err);
if (!user) return done(null, false);
// проверка пароля
if (!verifyPassword(password, user.passwordHash)) {
return done(null, false);
}
return done(null, user);
});
}
));
Библиотека password-hash предоставляет простой API для
создания и проверки хэшей:
const passwordHash = require('password-hash');
const hash = passwordHash.generate('mySecretPassword');
Сгенерированная строка включает алгоритм, соль и сам хэш. Это делает хранение безопаснее, так как одинаковые пароли дают разные хэши.
Проверка выполняется так:
const isValid = passwordHash.verify('mySecretPassword', hash);
При создании пользователя важно хэшировать пароль до сохранения в базу данных.
function registerUser(username, password) {
const hashedPassword = passwordHash.generate(password);
const user = new User({
username: username,
passwordHash: hashedPassword
});
return user.save();
}
Критический момент — хэширование должно происходить только на сервере. Любые попытки хранить пароль в открытом виде приводят к уязвимостям.
Интеграция с Passport.js требует явного вызова проверки пароля внутри стратегии:
passport.use(new LocalStrategy(
function(username, password, done) {
User.findOne({ username: username }, function(err, user) {
if (err) return done(err);
if (!user) return done(null, false);
const isValid = passwordHash.verify(password, user.passwordHash);
if (!isValid) {
return done(null, false);
}
return done(null, user);
});
}
));
В этом сценарии Passport не знает ничего о хэшировании — вся логика инкапсулирована в callback-функции.
Для работы с сессиями Passport требует определения двух функций:
passport.serializeUser(function(user, done) {
done(null, user.id);
});
passport.deserializeUser(function(id, done) {
User.findById(id, function(err, user) {
done(err, user);
});
});
Сериализация сохраняет минимальный идентификатор пользователя в сессии, а десериализация восстанавливает объект пользователя при каждом запросе.
Типичный стек использования local-стратегии включает Express middleware:
const express = require('express');
const passport = require('passport');
const session = require('express-session');
const app = express();
app.use(express.urlencoded({ extended: true }));
app.use(session({ secret: 'secretKey', resave: false, saveUninitialized: false }));
app.use(passport.initialize());
app.use(passport.session());
Маршрут логина:
app.post('/login',
passport.authenticate('local', {
successRedirect: '/dashboard',
failureRedirect: '/login'
})
);
Распространённые проблемы в реализации local-стратегии:
verifyОсобенно критична ошибка прямого сравнения:
if (password === user.passwordHash) // ошибка
Хотя password-hash обеспечивает базовую защиту, в
реальных системах часто применяются более устойчивые алгоритмы:
Дополнительно учитываются:
Passport позволяет детализировать причину отказа:
return done(null, false, { message: 'Неверный пароль' });
Это сообщение может использоваться для отображения UI, но не должно раскрывать, существует ли пользователь в системе.
Local-стратегия в связке с хэшированием формирует последовательность:
password-hash.verifyКаждый этап аутентификации в Passport.js реализуется через middleware. Это позволяет интегрировать проверку пользователя в HTTP-поток без явного управления состоянием.
Middleware-архитектура обеспечивает:
Local-стратегия часто используется параллельно с OAuth:
passport.use('local', new LocalStrategy(...));
passport.use('google', new GoogleStrategy(...));
Это позволяет комбинировать традиционную авторизацию и внешние провайдеры.
Хэширование пароля — это не просто техническая деталь, а фундаментальная часть модели безопасности:
Даже при использовании password-hash важно понимать, что безопасность зависит не только от алгоритма, но и от архитектуры всей системы аутентификации.