Гид по технологиям

Аутентификация пользователей в Node.js с Passport.js и PostgreSQL

7 min read Разработка Обновлено 05 Dec 2025
Аутентификация в Node.js с Passport.js и PostgreSQL
Аутентификация в Node.js с Passport.js и PostgreSQL

Крупный план клавиш клавиатуры

Важно: в примерах используется хеширование паролей через bcryptjs и хранение только хэшей паролей. Никогда не сохраняйте пароли в открытом виде.

Что вы реализуете

  • Таблица users в PostgreSQL с полями id, email и password.
  • Node.js-сервер на Express с эндпоинтами /auth/signup и /auth/login.
  • Вспомогательные функции для работы с базой: проверка существования email, создание пользователя, сравнение паролей.
  • Конфигурация Passport с локальными стратегиями для регистрации и входа.
  • Базовые рекомендации по тестированию, безопасности и соответствию требованиям конфиденциальности.

Почему этот подход работает

Passport.js отделяет логику аутентификации от маршрутов и упрощает замену стратегии (например, на JWT или OAuth). PostgreSQL обеспечивает надёжное хранение и ACID-свойства для пользовательских данных. bcryptjs используется для безопасного хеширования паролей.

Пререквизиты

  • Node.js (LTS) и npm
  • PostgreSQL
  • Базовые знания JavaScript и SQL

Создание базы данных и таблицы пользователей

В psql создайте базу данных nodeapp и таблицу users. Рекомендуется использовать VARCHAR вместо CHAR для полей, чтобы избежать лишних пробелов на конце строки.

CREATE DATABASE nodeapp;
CREATE TABLE users (
  id INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
  email VARCHAR(128) UNIQUE NOT NULL,
  password CHAR(60) NOT NULL
);

Примечание: CHAR(60) выбран потому, что стандартный bcrypt-хэш имеет длину около 60 символов. При желании используйте VARCHAR(255) для расширенной гибкости.

Создание Node-сервера (Express)

Создайте папку проекта, инициализируйте npm и установите необходимые пакеты:

mkdir postgres-auth
npm init -y
npm install express

Пример базового сервера в index.js:

const express = require("express");
const app = express();
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
app.listen(3000, () => console.log("Listening on port 3000"));

Запустите сервер: в консоли появится “Listening on port 3000”.

Подключение к PostgreSQL (node-postgres)

Установите драйвер:

npm install pg

Пример файла db.js, который создаёт клиент и подключается к базе:

const { Client } = require("pg");
const { user, host, database, password, port } = require("./dbConfig");

const client = new Client({
  user,
  host,
  database,
  password,
  port,
});

client.connect();

module.exports = client;

Файл dbConfig.js с локальными параметрами подключения (не храните реальные пароли в репозитории):

module.exports = {
  user: "postgres",
  host: "localhost",
  database: "nodeapp",
  password: "yourPassword",
  port: 5432,
};

Безопасность: используйте переменные окружения (process.env) и не коммитьте секреты в VCS.

Помощники для работы с базой (helper.js)

Создайте отдельный модуль helper.js, который инкапсулирует операции с пользователями. Это облегчает тестирование и позволяет избежать дублирования кода.

Установите bcryptjs:

npm install bcryptjs

Пример helper.js:

const client = require("./db.js");
const bcrypt = require("bcryptjs");

const emailExists = async (email) => {
  const data = await client.query("SELECT * FROM users WHERE email=$1", [
    email,
  ]);

  if (data.rowCount == 0) return false;
  return data.rows[0];
};

const createUser = async (email, password) => {
  const salt = await bcrypt.genSalt(10);
  const hash = await bcrypt.hash(password, salt);

  const data = await client.query(
    "INSERT INTO users(email, password) VALUES ($1, $2) RETURNING id, email, password",
    [email, hash]
  );

  if (data.rowCount == 0) return false;
  return data.rows[0];
};

const matchPassword = async (password, hashPassword) => {
  const match = await bcrypt.compare(password, hashPassword);
  return match;
};

module.exports = { emailExists, createUser, matchPassword };

Пояснение:

  • emailExists возвращает false или объект пользователя из БД.
  • createUser хеширует пароль и сохраняет запись.
  • matchPassword сравнивает введённый пароль с хешем.

Установка и настройка Passport.js

Passport.js — это middleware для Node.js, который поддерживает множество стратегий аутентификации. Для локальной (email/password) аутентификации используем passport-local.

Установка:

npm install passport
npm install passport-local

Создайте файл passportConfig.js и подключите локальную стратегию и вспомогательные функции:

const LocalStrategy = require("passport-local");
const { emailExists, createUser, matchPassword } = require("./helper");

module.exports = (passport) => {
  passport.use(
    "local-signup",
    new LocalStrategy(
      {
        usernameField: "email",
        passwordField: "password",
      },
      async (email, password, done) => {
        try {
          const userExists = await emailExists(email);

          if (userExists) {
            return done(null, false);
          }

          const user = await createUser(email, password);
          return done(null, user);
        } catch (error) {
          done(error);
        }
      }
    )
  );

  passport.use(
    "local-login",
    new LocalStrategy(
      {
        usernameField: "email",
        passwordField: "password",
      },
      async (email, password, done) => {
        try {
          const user = await emailExists(email);
          if (!user) return done(null, false);
          const isMatch = await matchPassword(password, user.password);
          if (!isMatch) return done(null, false);
          return done(null, { id: user.id, email: user.email });
        } catch (error) {
          return done(error, false);
        }
      }
    )
  );
};

Пояснение: каждая стратегия вызывает done(error, user, info). Мы отключили сессии (см. ниже про JWT и сессии).

Маршруты регистрации и входа

В файле server.js подключите Passport и зарегистрируйте маршруты:

const express = require("express");
const app = express();
const passport = require("passport");
require("./passportConfig")(passport);

app.use(express.json());
app.use(express.urlencoded({ extended: true }));

app.post(
  "/auth/signup",
  passport.authenticate("local-signup", { session: false }),
  (req, res, next) => {
    res.json({
      user: req.user,
    });
  }
);

app.post(
  "/auth/login",
  passport.authenticate("local-login", { session: false }),
  (req, res, next) => {
    res.json({ user: req.user });
  }
);

app.listen(3000, () => console.log("Listening on port 3000"));

Отключённые сессии ({ session: false }) — это удобный вариант для API, где вы хотите возвращать токен (например, JWT) и хранить состояние на клиенте.

Альтернативы хранению состояния

  • Сессии на сервере (express-session + connect-pg-simple): состояние хранится в базе/Redis и управляется сервером.
  • JWT (JSON Web Token): сервер выдаёт токен при логине, клиент хранит его и отправляет в Authorization заголовке.

Выбор зависит от требований: JWT проще масштабировать (без состояния на сервере), сессии удобнее для быстрого отзыва доступа и централизации контроля.

Проверка API: unit-тесты и интеграционные тесты

Для тестирования используйте Jest и супертест (supertest) для HTTP-запросов к серверу.

Пример тестов (упрощённо):

npm install --save-dev jest supertest

Пример теста регистрации:

const request = require("supertest");
const app = require("../server"); // экспортируйте app в server.js

describe("POST /auth/signup", () => {
  it("создаёт нового пользователя", async () => {
    const res = await request(app).post('/auth/signup').send({
      email: 'test@example.com',
      password: 'Password123'
    });
    expect(res.statusCode).toBe(200);
    expect(res.body.user).toHaveProperty('email', 'test@example.com');
  });
});

Критерии приёмки:

  • Успешная регистрация возвращает 200 и объект user без поля password.
  • Повторная регистрация с тем же email возвращает ошибку/403.
  • Успешный вход возвращает user.id и user.email.

Важно: в тестовой среде используйте отдельную тестовую базу и сбрасывайте данные между тестами.

Риски и меры безопасности

  • Хранение паролей: храните только хэши (bcrypt). Не храните открытые пароли.
  • Brute-force: используйте ограничение частоты (rate limiting) для эндпоинтов авторизации.
  • HTTPS: всегда шифруйте трафик в продакшене.
  • Заголовки безопасности: используйте helmet для общих заголовков безопасности.
  • Валидация входных данных: проверяйте формат email и минимальную длину пароля.
  • CORS: настраивайте разрешённые источники для API.
  • Логи: не логируйте пароли или токены.

Рекомендации по пакетам:

  • express-rate-limit для ограничения запросов.
  • helmet для безопасных HTTP-заголовков.
  • express-validator или Joi для валидации схемы входящих данных.

Соответствие конфиденциальности (GDPR-подобные требования)

  • Минимизируйте собираемые данные: храните только необходимые поля.
  • Удаление по запросу: реализуйте механизм удаления учётной записи и связанных данных.
  • Право на переносимость: предоставляйте экспорт данных по запросу.
  • Обработка паролей: используйте надёжное хеширование и защиту от утечек.

Юридическая заметка: при работе с персональными данными уточните требования локального законодательства и требования GDPR, если они применимы.

Модель зрелости аутентификации (уровни)

  • Уровень 0: без аутентификации — открытые API.
  • Уровень 1: базовая локальная аутентификация (email/password, bcrypt).
  • Уровень 2: сессии с серверным хранилищем и возможностью отзыва.
  • Уровень 3: JWT с ротацией рефреш-токенов и защитой от CSRF.
  • Уровень 4: многофакторная аутентификация (MFA), мониторинг аномалий.

Этот пример покрывает уровень 1–2 и служит отправной точкой для развития.

Шаблон playbook для быстрой настройки (SOP)

  1. Настроить PostgreSQL и создать базу nodeapp.
  2. Инициализировать проект npm и установить express, pg, passport, passport-local, bcryptjs.
  3. Создать dbConfig.js и db.js (использовать переменные окружения в проде).
  4. Создать helper.js с функциями emailExists, createUser, matchPassword.
  5. Создать passportConfig.js с локальными стратегиями.
  6. Создать server.js, экспортировать app для тестов и начать прослушивание порта.
  7. Добавить rate limiting и helmet.
  8. Написать unit и интеграционные тесты (Jest + supertest).
  9. Настроить CI для запуска тестов и проверок безопасности.
  10. Развернуть на хостинге, настроить HTTPS и мониторинг.

Контрольный список ролей

Разработчик:

  • Реализовать helper.js и passportConfig.js
  • Написать unit-тесты
  • Не хранить секреты в репозитории

DevOps/Инфраструктура:

  • Настроить базу данных и резервное копирование
  • Обеспечить HTTPS и доступность
  • Мониторинг и алерты

Инженер по безопасности:

  • Провести ревью зависимостей
  • Настроить rate limiting и WAF при необходимости

Тестовые сценарии и критерии приёмки

  • Успешная регистрация с валидным email и паролем -> 200, user.email возвращён, password не возвращён.
  • Регистрация с уже существующим email -> 400/409, тело ответа с описанием ошибки.
  • Вход с правильными учетными данными -> 200, возвращается id и email.
  • Вход с неправильным паролем -> 401, без деталей о причинах (не раскрывать, что именно неверно).
  • Попытка SQL-инъекции в поле email должна быть нейтрализована параметризованными запросами.

Миграции и совместимость

  • Для версионирования схемы используйте миграционные инструменты (например, node-pg-migrate, knex migrate, Flyway).
  • Убедитесь, что хэши старых паролей корректно распознаются при смене algorithма: добавьте план миграции паролей.

Решение: когда это не подходит

  • Если приложение требует масштабной авторизации и делегирования прав — рассмотрите OAuth2 / OpenID Connect и стороннего провайдера (Auth0, Keycloak).
  • Для полностью безсерверных решений существует необходимость в других паттернах авторизации (например, Cognito или Firebase Auth).

Диаграмма выбора стратегии (Mermaid)

flowchart TD
  A[Нужно аутентифицировать пользователей?] --> B{Нужны ли сессии на сервере?}
  B -- Да --> C[Использовать express-session + хранение в БД/Redis]
  B -- Нет --> D{Требуется масштабирование без состояния?}
  D -- Да --> E[Использовать JWT с ротацией рефреш-токенов]
  D -- Нет --> F[Использовать Passport.js с локальными стратегиями]
  C --> G[Добавить защиту от CSRF и управление сессиями]
  E --> H[Реализовать чёрный список / ротацию токенов]
  F --> I[Подключить bcryptjs и защиту от brute-force]

Примеры команд развёртывания и мониторинга

  • Перенос конфигурации в переменные окружения:
    • DATABASE_URL, JWT_SECRET, NODE_ENV
  • Настройка PM2 или systemd для процесса Node.
  • Настройка ежедневных бэкапов PostgreSQL.

Социальные превью

OG title: Аутентификация в Node.js с Passport.js и PostgreSQL OG description: Пошаговое руководство по добавлению безопасной аутентификации (регистрация, вход) в приложение на Node.js с PostgreSQL и Passport.js.

Краткое объявление (100–200 слов): Если вам нужно быстро добавить безопасную аутентификацию в Node-приложение, это руководство даст рабочие шаги: таблицу users в PostgreSQL, вспомогательные функции для работы с БД, конфигурацию Passport.js и маршруты регистрации/входа. Также рассмотрены альтернативы (JWT, сессии), рекомендации по безопасности и тестированию.

Итог

Ключевые выводы:

  • Passport.js упрощает реализацию локальной аутентификации и легко заменяется на другие стратегии.
  • Храните только хэши паролей (bcrypt) и используйте параметризованные запросы.
  • Тестируйте эндпоинты автоматизированно и используйте отдельную тестовую базу.
  • Добавьте защитные меры: rate limiting, HTTPS, helmet и валидацию входящих данных.

Важно: начинайте с базовой реализации и постепенно улучшайте зрелость системы (ротация токенов, MFA, аудит), ориентируясь на требования безопасности и удобство пользователей.

Поделиться: X/Twitter Facebook LinkedIn Telegram
Автор
Редакция

Похожие материалы

TOML в Rust: чтение и запись
Программирование

TOML в Rust: чтение и запись

Анализ тональности на Python с VADER и Tkinter
Обработка текста

Анализ тональности на Python с VADER и Tkinter

Проверить прокси в Windows
Безопасность

Проверить прокси в Windows

Темы рабочего стола в Ubuntu 18.04 LTS
Linux

Темы рабочего стола в Ubuntu 18.04 LTS

Что делать, если Logitech G Pro Wireless не работает
Техподдержка

Что делать, если Logitech G Pro Wireless не работает

Dev Drive в Windows 11 — как начать
Разработка

Dev Drive в Windows 11 — как начать