Passport.js для JavaScript (Node.js): полное руководство с примерами

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Что такое Passport.js и зачем он нужен?

Passport.js — это самая популярная и гибкая библиотека для аутентификации в приложениях на Node.js. Она спроектирована по принципу "middleware" (промежуточного слоя) для Express.js, что позволяет легко интегрировать её в любой веб-сервер. Основная задача Passport.js — упростить процесс проверки подлинности пользователей, предоставляя единый интерфейс для работы с десятками различных стратегий аутентификации.

Зачем нужна эта библиотека? В современной веб-разработке аутентификация — это не просто проверка логина и пароля. Пользователи ожидают возможность входа через социальные сети (Google, Facebook, VK), через корпоративные системы (LDAP, SAML), с помощью JWT-токенов или одноразовых кодов. Каждый из этих методов требует своей логики, своих API-запросов и обработки ошибок. Passport.js абстрагирует эту сложность, предлагая единый паттерн: вы выбираете "стратегию" (Strategy), настраиваете её, и библиотека берёт на себя всю рутинную работу по обработке запросов, сессий и перенаправлений.

Ключевые преимущества Passport.js:

  • Модульность: более 500 стратегий, покрывающих практически все существующие методы аутентификации.
  • Простота интеграции: работает как middleware Express.js, что делает код чистым и предсказуемым.
  • Независимость от базы данных: библиотека не навязывает способ хранения пользователей — вы сами решаете, как и где хранить данные (MongoDB, PostgreSQL, файлы).
  • Безопасность: встроенная поддержка сессий, защита от CSRF (через дополнительные модули) и правильная обработка паролей.
  • Гибкость: вы можете комбинировать стратегии, создавать собственные и настраивать поведение под любые бизнес-требования.

Эта статья станет вашим исчерпывающим руководством. Мы начнём с установки, разберём быстрый старт, подробно изучим все основные методы и функции, а затем закрепим знания на реальном практическом примере.

Установка библиотеки

Установка Passport.js и необходимых стратегий выполняется через менеджер пакетов npm. Базовая установка включает ядро библиотеки и одну из стратегий (чаще всего passport-local для аутентификации по логину/паролю).

# Установка ядра Passport.js
npm install passport

# Установка стратегии для локальной аутентификации (логин/пароль)
npm install passport-local

# Установка стратегии для JWT (JSON Web Tokens)
npm install passport-jwt

# Установка стратегии для OAuth 2.0 (Google, Facebook и др.)
npm install passport-google-oauth20

# Дополнительно: для работы с сессиями (если не используете JWT)
npm install express-session

# Для хеширования паролей (рекомендуется)
npm install bcryptjs

Обратите внимание: passport — это только ядро. Конкретные методы аутентификации (через Google, Facebook, локально и т.д.) реализуются через отдельные пакеты-стратегии. Всего их несколько сотен, и вы можете найти нужную на официальном сайте passportjs.org/packages/.

Быстрый старт с примером кода

Давайте создадим минимальное приложение на Express.js с локальной аутентификацией (логин и пароль). Этот пример покажет базовую архитектуру работы Passport.js.

Шаг 1: Создайте файл app.js и установите зависимости.

const express = require('express');
const passport = require('passport');
const LocalStrategy = require('passport-local').Strategy;
const session = require('express-session');
const bcrypt = require('bcryptjs');

const app = express();

// Настройка middleware для парсинга тела запроса
app.use(express.urlencoded({ extended: false }));
app.use(express.json());

// Настройка сессий (обязательно для passport с сессиями)
app.use(session({
    secret: 'your-secret-key',
    resave: false,
    saveUninitialized: false
}));

// Инициализация Passport.js
app.use(passport.initialize());
app.use(passport.session());

Шаг 2: Настройка стратегии (passport-local).

// Мок-база данных пользователей (в реальном проекте замените на MongoDB/PostgreSQL)
const users = [];

// Стратегия проверки логина и пароля
passport.use(new LocalStrategy(
    {
        usernameField: 'email', // Поле для имени пользователя (может быть 'username' или 'email')
        passwordField: 'password' // Поле для пароля
    },
    async (email, password, done) => {
        try {
            // Ищем пользователя по email
            const user = users.find(u => u.email === email);
            if (!user) {
                return done(null, false, { message: 'Неверный email или пароль' });
            }

            // Сравниваем пароль с хешем
            const isMatch = await bcrypt.compare(password, user.password);
            if (!isMatch) {
                return done(null, false, { message: 'Неверный email или пароль' });
            }

            // Успешная аутентификация
            return done(null, user);
        } catch (err) {
            return done(err);
        }
    }
));

Шаг 3: Сериализация и десериализация пользователя (для сессий).

// Сохраняем ID пользователя в сессию
passport.serializeUser((user, done) => {
    done(null, user.id);
});

// По ID из сессии получаем полный объект пользователя
passport.deserializeUser((id, done) => {
    const user = users.find(u => u.id === id);
    done(null, user);
});

Шаг 4: Создание маршрутов.

// Маршрут для регистрации (создаём пользователя)
app.post('/register', async (req, res) => {
    try {
        const { email, password } = req.body;
        
        // Проверяем, существует ли пользователь
        const existingUser = users.find(u => u.email === email);
        if (existingUser) {
            return res.status(400).json({ message: 'Пользователь уже существует' });
        }

        // Хешируем пароль
        const hashedPassword = await bcrypt.hash(password, 10);
        
        // Создаём пользователя
        const newUser = {
            id: users.length + 1,
            email: email,
            password: hashedPassword
        };
        users.push(newUser);

        res.status(201).json({ message: 'Пользователь создан', userId: newUser.id });
    } catch (err) {
        res.status(500).json({ message: 'Ошибка сервера' });
    }
});

// Маршрут для входа (аутентификация)
app.post('/login', passport.authenticate('local', {
    successRedirect: '/profile',
    failureRedirect: '/login',
    failureFlash: false // Для сообщений об ошибках используйте connect-flash
}));

// Защищённый маршрут (только для аутентифицированных пользователей)
app.get('/profile', (req, res) => {
    if (!req.isAuthenticated()) {
        return res.status(401).json({ message: 'Не авторизован' });
    }
    res.json({ 
        message: 'Добро пожаловать!', 
        user: { id: req.user.id, email: req.user.email } 
    });
});

// Маршрут для выхода
app.get('/logout', (req, res) => {
    req.logout((err) => {
        if (err) { return next(err); }
        res.redirect('/');
    });
});

// Запуск сервера
app.listen(3000, () => {
    console.log('Сервер запущен на порту 3000');
});

Этот минимальный пример показывает, как работает Passport.js: стратегия проверяет учётные данные, сериализация сохраняет пользователя в сессию, а middleware req.isAuthenticated() проверяет статус. Теперь разберём каждый метод подробнее.

Основные методы и функции Passport.js

В этом разделе мы рассмотрим 10 ключевых методов и функций библиотеки. Для каждого дано описание, параметры и рабочий пример кода.

1. passport.use(strategy)

Что делает: Регистрирует новую стратегию аутентификации. Это основной метод для подключения любого способа входа (локальный, Google, JWT и т.д.).

Параметры:

  • strategy (Object) — экземпляр стратегии, созданный через конструктор (например, new LocalStrategy(...)).

Рабочий пример:

const GoogleStrategy = require('passport-google-oauth20').Strategy;

passport.use(new GoogleStrategy({
    clientID: 'YOUR_GOOGLE_CLIENT_ID',
    clientSecret: 'YOUR_GOOGLE_CLIENT_SECRET',
    callbackURL: 'http://localhost:3000/auth/google/callback'
}, (accessToken, refreshToken, profile, done) => {
    // Здесь вы можете найти или создать пользователя в БД
    return done(null, profile);
}));

2. passport.initialize()

Что делает: Инициализирует Passport.js как middleware Express. Без этого вызова библиотека не будет работать. Добавляет в объект req методы login(), logout(), isAuthenticated().

Параметры: Нет.

Рабочий пример:

const app = express();
app.use(passport.initialize()); // Теперь req.login, req.logout, req.isAuthenticated доступны

3. passport.session()

Что делает: Middleware для работы с сессиями. Если вы используете сессионную аутентификацию (не JWT), этот метод обязателен. Он автоматически вызывает deserializeUser при каждом запросе, чтобы восстановить объект пользователя из сессии.

Параметры: Нет.

Рабочий пример:

app.use(session({ secret: 'keyboard cat' }));
app.use(passport.initialize());
app.use(passport.session()); // Восстанавливает req.user из сессии

4. passport.authenticate(strategy, options)

Что делает: Запускает процесс аутентификации для указанной стратегии. Это middleware, который можно использовать в маршрутах. В случае успеха пользователь сохраняется в сессию (если используется passport.session()), и управление передаётся следующему middleware.

Параметры:

  • strategy (String) — название зарегистрированной стратегии (например, 'local', 'google', 'jwt').
  • options (Object) — необязательные параметры:
    • successRedirect (String) — URL для перенаправления при успехе.
    • failureRedirect (String) — URL для перенаправления при неудаче.
    • failureFlash (Boolean/String) — показывать flash-сообщение об ошибке.
    • session (Boolean) — сохранять ли пользователя в сессию (по умолчанию true).

Рабочий пример:

// Простой вариант с редиректами
app.post('/login', passport.authenticate('local', {
    successRedirect: '/dashboard',
    failureRedirect: '/login',
    failureFlash: true
}));

// Вариант с кастомным колбэком (для API)
app.post('/api/login', (req, res, next) => {
    passport.authenticate('local', (err, user, info) => {
        if (err) { return next(err); }
        if (!user) { return res.status(401).json({ message: info.message }); }
        req.logIn(user, (err) => {
            if (err) { return next(err); }
            return res.json({ message: 'Успешный вход', user: user });
        });
    })(req, res, next);
});

5. req.login(user, callback) / req.logIn(user, callback)

<

Рекомендаций