Внедрите JWT-аутентификацию в API Node.js как профессионал.

Последнее обновление: 02/11/2026
  • JWT обеспечивает масштабируемую аутентификацию без сохранения состояния для API Node.js, плавно интегрируясь с маршрутами и промежуточным ПО Express.
  • Сочетание Express, Mongoose, jsonwebtoken, bcrypt, Joi и dotenv создает безопасную, модульную основу для процессов аутентификации пользователей.
  • Валидация JWT на основе JWKS позволяет API Node.js доверять внешним серверам авторизации и корректно обеспечивать соблюдение областей действия и утверждений.
  • Тщательная проверка, четкая обработка ошибок и структурированное тестирование имеют решающее значение для обеспечения надежности конечных точек, защищенных JWT.

Аутентификация через JWT API в Node.js

Если вы разрабатываете API с помощью Node.js, добавление корректной аутентификации с использованием JWT может поначалу показаться сложной задачей, но на самом деле это совсем не так. Используя несколько правильно подобранных библиотек, четкую структуру и передовые методы проверки и безопасности, вы можете защитить свои конечные точки, сохранив при этом чистоту и удобство сопровождения кода.

В этом руководстве мы рассмотрим, как реализовать аутентификацию на основе JWT в API Node.js с использованием Express, MongoDB и таких инструментов, как jsonwebtoken, bcrypt, Joi и dotenv, а также увидим, как проверять токены с помощью конечной точки JWKS из сервера авторизации в более корпоративных сценариях. Вы научитесь проектировать структуру проекта, создавать модели и маршруты, генерировать и проверять токены, добавлять промежуточное ПО для аутентификации и связывать все компоненты таким образом, чтобы доступ к защищенным ресурсам имели только авторизованные пользователи.

Что дают JSON Web Tokens (JWT) вашим API на Node.js

JSON Web Tokens (JWT) — это компактные, безопасные для URL-адресов токены, содержащие набор утверждений и позволяющие двум сторонам обмениваться аутентифицированной информацией без сохранения состояния сессии на стороне сервера. В контексте API Node.js это означает, что после авторизации пользователя и выдачи JWT каждый последующий запрос может быть проверен вашим бэкэндом с использованием только самого токена и секретного или открытого ключа, что обеспечивает гораздо лучшую масштабируемость по сравнению с традиционными серверными сессиями.

Типичный JWT состоит из трех частей: заголовка, полезной нагрузки и подписи, все они закодированы в формате Base64URL и разделены точками, например. xxxxx.yyyyy.zzzzz. В заголовке обычно указывается алгоритм и тип токена, полезная нагрузка содержит данные о пользователе, такие как идентификатор, роли или разрешения, а подпись обеспечивает целостность, чтобы токен нельзя было незаметно изменить.

При реализации JWT в API Node.js обычно используется токен в качестве токена носителя. Authorization HTTP-заголовок, например Authorization: Bearer <token>а затем декодировать и проверить его внутри вашего промежуточного ПО Express или обработчиков маршрутов. Если токен действителен, вы можете прикрепить декодированную полезную нагрузку к объекту запроса и использовать ее позже для принятия решений об авторизации или для персонализации ответа.

Одним из главных преимуществ JWT является их независимость от языка программирования и широкая поддержка в различных экосистемах, что делает их отличным выбором для защиты API, используемых React, Vue, мобильными приложениями или любыми сторонними клиентами. В сочетании с надежной проверкой и надлежащим управлением ключами они позволяют сервисам Node.js беспрепятственно участвовать в архитектурах на основе OAuth 2.0 и OpenID Connect.

Обзор проекта: API на Node.js с аутентификацией JWT.

Представим себе простой, но реалистичный API на Node.js, где пользователи могут регистрироваться, входить в систему и получать доступ к защищенным конечным точкам только после предъявления действительного JWT-токена. Для маршрутизации мы будем использовать Express, для интеграции с MongoDB — Mongoose, для создания и проверки токенов — jsonwebtoken, для безопасного хеширования паролей — bcrypt, для проверки входных данных — Joi, а для управления конфигурацией — dotenv.

Аккуратная структура папок помогает поддерживать понятность по мере роста проекта, поэтому вместо того, чтобы сваливать все в один файл, мы определим базовую структуру с отдельными модулями для конфигурации, базы данных, моделей, маршрутов и промежуточного ПО. Такой модульный подход также упрощает модульное тестирование отдельных частей процесса аутентификации.

В общих чертах, API будет предоставлять набор REST-конечных точек для регистрации и входа пользователей, а также как минимум один защищенный ресурс, доступ к которому возможен только при наличии действительного JWT в заголовках запроса. В ходе изучения мы рассмотрим, как проверять полезную нагрузку запросов, хешировать и сравнивать пароли, генерировать токены, содержащие идентификатор пользователя, и интегрировать промежуточное ПО аутентификации, проверяющее токены при входящих вызовах.

Аналогичный подход можно распространить на более сложные системы, включая те, которые интегрируются с внешним сервером авторизации и используют конечные точки JWKS для проверки входящих токенов доступа от клиентов OAuth 2.0. Второй сценарий особенно распространен, когда вы делегируете аутентификацию поставщикам удостоверений или вам необходимо поддерживать единый вход в систему для нескольких сервисов.

Прежде чем перейти к детальной реализации, давайте обозначим ключевые компоненты среды, на которые мы будем полагаться, и объясним, почему каждая зависимость важна для безопасной обработки JWT в Node.js.

Основные зависимости для аутентификации с помощью JWT в Node.js

Express является основой многих API Node.js, предоставляя минималистичный, но гибкий фреймворк для маршрутизации, промежуточного ПО и обработки HTTP-запросов. В нашем случае Express будет служить платформой, где мы будем регистрировать маршруты, например: /api/users or /api/authи где мы подключаем промежуточное ПО для проверки JWT, которое защищает конфиденциальные конечные точки.

Mongoose — это библиотека объектного моделирования данных (ODM), которая упрощает взаимодействие с MongoDB через схемы и модели, вместо работы непосредственно с прямыми запросами. Мы будем использовать это для определения User модель со свойствами, такими как имя, электронная почта и пароль, и для сохранения или извлечения этих документов из базы данных типобезопасным способом.

Команда jsonwebtoken Эта библиотека является стандартным выбором в Node.js для создания и проверки JWT с использованием секретного или открытого ключа. При авторизации мы подпишем токен, содержащий идентификатор пользователя (и любые другие необходимые нам данные), а позже проверим этот токен на защищенных маршрутах, отклоняя любой запрос, содержащий недействительный, некорректный или просроченный токен.

Для обеспечения безопасности паролей используется библиотека bcrypt, которая хеширует пароли в открытом виде перед сохранением и сравнивает предоставленные учетные данные с хешированными значениями во время аутентификации. Это крайне важно, поскольку хранение паролей в необработанном виде или использование слабых стратегий хеширования подвергает пользователей огромному риску в случае утечки данных из базы данных, в то время как bcrypt предоставляет проверенное, испытанное в боевых условиях решение.

Joi играет важную роль в проверке входящих данных на границе API, описывая схемы объектов и проверяя, что каждый запрос ведет себя должным образом. Например, мы можем установить, что электронное письмо должно быть правильно отформатировано, что пароль имеет минимальную длину и что определенные поля являются обязательными, что значительно снижает вероятность попадания некорректных или вредоносных данных в нашу логику.

Наконец, dotenv позволяет загружать переменные окружения из .env файл, в котором секретные данные, такие как ключи подписи JWT, URL-адреса баз данных или параметры конфигурации, хранятся вне исходного кода. Это помогает избежать жесткого кодирования конфиденциальных значений и способствует лучшему разделению конфигураций для разработки, тестирования и производства.

Настройка сервера Express и среды.

Точкой входа в наш API обычно является index.js файл, где мы инициализируем Express, регистрируем промежуточное ПО и монтируем определения маршрутов. В этом файле нам потребуется конфигурация нашей базы данных, модули маршрутизации и любое глобальное промежуточное ПО, такое как парсинг JSON-тела или CORS.

Сразу после загрузки зависимостей целесообразно вызвать require("dotenv").config() таким образом, переменные среды из .env файл становится доступен через process.env. Это включает в себя такие ключи, как JWT_PRIVATE_KEY, MONGO_URI или порт, на котором сервер будет прослушивать запросы, что обеспечивает гибкость и безопасность конфигурации.

Само приложение Express обычно использует app.use(express.json()) для анализа тел JSON-запросов и монтирования маршрутизаторов для определенных префиксов URL, таких как app.use("/api/users", usersRouter) и app.use("/api/auth", authRouter). Такое разделение позволяет изолировать маршруты, связанные с аутентификацией, и вопросы управления пользователями от других частей API.

После настройки среды и запуска Express следующим шагом является подключение базы данных MongoDB через специальный модуль, часто это db.js файл, где мы настраиваем логику подключения.

Настройка MongoDB с помощью Mongoose

В db.js В модуле мы обычно импортируем Mongoose и вызываем mongoose.connect() с использованием строки подключения к MongoDB, хранящейся в переменной среды. Мы также можем настроить такие параметры, как логика повторных попыток, унифицированная топология или пул соединений, чтобы обеспечить стабильную работу в производственных средах.

Обычно при успешном подключении в лог записывается сообщение, а ошибки обрабатываются корректно, так что если MongoDB недоступна, API запускается с понятной диагностикой. В полноценном приложении вы даже можете выбрать вариант завершения процесса в случае сбоя подключения к базе данных, поскольку от него зависит множество маршрутов.

Как только появится строка db.js Файл реализован, мы импортируем его из index.js и вызывать его на раннем этапе запуска приложения, чтобы убедиться, что наш API подключен к базе данных до обработки любого запроса. Такое разделение обеспечивает изоляцию и возможность повторного использования конфигурации, в то время как index.js по-прежнему сосредоточен на проблемах компании Express.

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

Создание модели пользователя с поддержкой JWT

Команда User модель, обычно размещаемая в /models/user.jsОпределяет структуру пользовательских документов, хранящихся в MongoDB, и инкапсулирует поведение, связанное с аутентификацией. Как минимум, мы включим такие свойства, как... name, email и passwordКроме того, при необходимости мы можем добавить метки времени, роли или другие метаданные.

Обычно поле электронной почты помечают как уникальное и обязательное, что гарантирует невозможность регистрации двух пользователей с одним и тем же адресом электронной почты. Аналогично, в поле для пароля не будет храниться текстовое значение; вместо этого мы будем хранить хеш bcrypt, сгенерированный во время регистрации или при обновлении пользователем своих учетных данных.

Интересное и весьма практичное проектное решение — добавить в схему пользователя метод для генерации JWT, который принимает идентификатор пользователя в качестве полезной нагрузки и подписывает его секретным ключом, определенным в среде выполнения. Этот метод можно вызвать во время входа в систему для создания токена, специфичного для данного пользователя, и он обеспечивает согласованность логики генерации токена с моделью, которая владеет данными об идентификации.

В сочетании с вспомогательными средствами валидации на основе Joi, модель пользователя становится центральным элементом всего, что связано с идентификацией: она описывает структуру пользовательских данных, проверяет входящие данные и генерирует токены, используемые остальной частью API.

Отсюда мы можем реализовать маршруты, отвечающие за регистрацию новых учетных записей и аутентификацию существующих пользователей, используя модель пользователя, bcrypt и Joi в тандеме.

Создание маршрута регистрации

Логика регистрации обычно находится в модуле маршрутизации, например, таком: /routes/users.jsгде мы определяем конечную точку, например: POST /api/users для обработки входящих запросов на регистрацию. Этот маршрут проверит полезную нагрузку с помощью Joi, проверит, используется ли уже указанный адрес электронной почты, хеширует пароль, создаст пользователя и сохранит его в базе данных.

Прежде чем сохранять какие-либо данные, мы можем использовать схему Joi, которая обеспечивает соблюдение таких требований, как обязательное указание имени и адреса электронной почты, правильный формат электронной почты и минимальная длина пароля. Если проверка не удалась, маршрут отвечает соответствующим кодом состояния ошибки и сообщением, предотвращая попадание некорректных данных в бизнес-логику.

Если адрес электронной почты еще не существует, мы генерируем соль bcrypt и хешируем пароль, заменяя исходный пароль его хешированной версией в объекте пользователя. Именно это хешированное значение в конечном итоге и хранится в MongoDB, что значительно ограничивает последствия потенциальных утечек данных.

После сохранения данных нового пользователя некоторые реализации также сразу же генерируют JWT и возвращают его в заголовке или теле ответа, так что пользователь считается аутентифицированным сразу после регистрации. Для использования других API может потребоваться отдельный шаг авторизации в зависимости от требований безопасности системы.

После завершения регистрации, для входа в систему можно будет использовать ту же логику проверки, сосредоточившись на проверке учетных данных и выдаче токенов.

Реализация маршрута авторизации и генерации токенов.

Процесс авторизации обычно обрабатывается следующим образом: /routes/auth.jsс конечной точкой, например: POST /api/auth Получает адрес электронной почты и пароль в теле запроса. В этом маршруте снова используется Joi для проверки наличия и правильной структуры обоих полей перед попыткой аутентификации пользователя.

После проверки маршрут запрашивает у базы данных пользователя с указанным адресом электронной почты, и если находит его, использует bcrypt для сравнения предоставленного пароля с сохраненным хешем. Если сравнение не удается, запрос отклоняется с соответствующим сообщением об ошибке; в противном случае мы переходим к выпуску токена.

В момент успешной аутентификации мы вызываем метод генерации токена, определенный в модели пользователя, который создает JWT, содержащий идентификатор пользователя (и, возможно, другие утверждения), и подписывает его секретным ключом. Затем этот токен может быть отправлен клиенту, часто в теле ответа или в пользовательском заголовке, где фронтенд или внешний потребитель сохраняет и повторно использует его для будущих запросов.

С точки зрения клиента, каждый последующий вызов к защищенным конечным точкам будет включать этот JWT в запрос. Authorization в заголовке используется токен носителя, именно то, что будет искать наше промежуточное ПО. На стороне сервера наличие выделенного промежуточного ПО для аутентификации гарантирует, что нам не придется повторять логику проверки токена в каждом маршруте.

Прежде чем углубляться в детали этого промежуточного ПО, стоит отметить, что этот же шаблон хорошо интегрируется с React или другими SPA-фреймворками, где потоки на основе JWT обычно используются как для аутентификации, так и для простой авторизации.

Создание промежуточного ПО аутентификации для защиты маршрутов.

Промежуточное ПО аутентификации, часто реализуемое в /middleware/auth.jsВыступает в роли привратника для любого маршрута, требующего аутентификации, перехватывая запросы до того, как они достигнут обработчика маршрута. Его основная задача — считывать JWT из Authorization Проверьте заголовок и внедрите декодированную полезную нагрузку в объект запроса для дальнейшего использования.

Промежуточное программное обеспечение начинает работу с проверки того, что Authorization Заголовок существует и соответствует ожидаемому. Bearer <token> формат; если токен отсутствует или имеет некорректный формат, система немедленно выдает код состояния "несанкционированный доступ". Это гарантирует, что незащищенные запросы случайно не проникнут в защищенные конечные точки.

При наличии токена промежуточное ПО вызывает соответствующую функцию. jwt.verify() (из jsonwebtoken библиотека), передавая токен и секретный или открытый ключ, используемый для подписи. Если проверка не удается из-за истечения срока действия, несоответствия подписи или любой другой проблемы, промежуточное ПО отвечает ошибкой; в противном случае оно перехватывает декодированную полезную нагрузку.

Во многих реализациях эта декодированная полезная нагрузка прикрепляется к req.user или аналогичное свойство, чтобы обработчики маршрутов, расположенные ниже по потоку, могли получать доступ к утверждениям, связанным с пользователем, без необходимости повторного анализа или проверки токена. Наконец, происходит вызов промежуточного программного обеспечения. next() передать управление следующей функции в конвейере Express.

Объединив это промежуточное ПО с определениями маршрутов, мы можем легко пометить одни конечные точки как общедоступные, а другие как защищенные, просто добавив промежуточное ПО в цепочку обработки запросов для этих маршрутов.

Доступ к защищенным ресурсам с помощью JWT

Распространенный сценарий использования после внедрения аутентификации — это предоставление маршрута, который получает профиль текущего пользователя или список пользователей, доступный только тем, кто предъявит действительный токен. Например, в /routes/users.js, возможно, будет GET /api/users/me Конечная точка, возвращающая информацию о вошедшем в систему пользователе.

Для защиты этого маршрута мы подключаем промежуточное ПО аутентификации, чтобы любой запрос, обращающийся к нему, содержал действительный JWT; в противном случае промежуточное ПО прервет запрос до выполнения фактического обработчика. Поскольку декодированная полезная нагрузка уже прикреплена к req.userОбработчик может получить идентификатор пользователя непосредственно из токена и выполнить соответствующий запрос к базе данных.

Этот подход гарантирует, что бизнес-логике не важен способ аутентификации; она просто доверяет наличию проверенной полезной нагрузки и сосредотачивается на получении или изменении данных домена. В более сложных конфигурациях вы также можете встраивать роли, разрешения или области действия в токен и использовать их для запуска проверок авторизации в обработчиках.

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

На этом этапе мы рассмотрели автономную настройку JWT с использованием секрета, хранящегося в нашем хранилище. .env файл, но многие производственные системы также интегрируются с внешними серверами авторизации и используют конечные точки JWKS для проверки токенов; именно здесь вступает в игру промежуточное ПО Express для API, защищенных OAuth.

Использование конечной точки JWKS для проверки JWT в Node.js

В более сложных архитектурах, особенно тех, которые используют OAuth 2.0 и OpenID Connect, API Node.js часто получают токены доступа, выданные внешним сервером авторизации, вместо того, чтобы генерировать JWT самостоятельно. В этом случае API должен проверять токены, подписанные асимметричными ключами, обычно RSA или EC, где закрытый ключ хранится только на сервере авторизации.

Распространенным решением является использование библиотеки промежуточного ПО Express, которая получает наборы ключей JSON Web Key Sets (JWKS) из настроенной конечной точки, предоставляемой сервером авторизации. Эта конечная точка JWKS предоставляет открытые ключи в стандартном формате, что позволяет API проверять входящие подписи JWT без необходимости управления закрытыми ключами.

Например, вы можете установить такой пакет, как... express-oauth-jwt и настройте его с помощью URL-адреса JWKS, например: https://idsvr.example.com/oauth/v2/oauth-anonymous/jwksа затем подключите промежуточное ПО к маршрутам вашего API на Node.js. После интеграции промежуточное программное обеспечение автоматически обрабатывает большинство задач проверки токенов на низком уровне.

При такой конфигурации библиотека выполняет поиск kid (Идентификатор ключа) из заголовка JWT, загружает соответствующий открытый ключ из конечной точки JWKS (если он еще не был кэширован) и проверяет подпись, используя этот ключ. В зависимости от настроек, программа также проверяет срок действия токена, эмитента, аудиторию и другие стандартные поля.

После успешной проверки разобранный JWT и содержащиеся в нем данные становятся доступны на Express. request объект, позволяющий вашим обработчикам проверять области действия, идентификаторы пользователей или пользовательские атрибуты в целях авторизации и ведения журналов. Если что-то пойдёт не так (например, срок действия токена истек или подпись не совпадает), промежуточное ПО ответит соответствующими кодами ошибок HTTP и укажет причину. WWW-Authenticate заголовка.

Области действия, утверждения и логика авторизации в вашем API

Как только ваш API на Node.js начнет доверять JWT, либо потому что он был подписан напрямую, либо потому что его проверило промежуточное ПО на основе JWKS, следующим шагом будет использование его утверждений и областей действия для реализации авторизации. Здесь вы выходите за рамки простой аутентификации и начинаете предоставлять или запрещать доступ в зависимости от того, что разрешено делать пользователю.

Как правило, области действия представляют собой разрешения с крупной детализацией, например: read:users or write:ordersи обычно они включаются в JWT в рамках таких претензий, как... scope or scopes. API может проверить наличие необходимой области видимости перед обработкой запроса, затрагивающего определенные бизнес-данные, и вернуть ответ с сообщением о запрете, если она отсутствует.

Аналогичным образом, такие данные, как идентификатор пользователя, адрес электронной почты, роль или информация об арендаторе, позволяют внедрять более детальные правила; например, гарантировать, что пользователи получают доступ только к своим собственным записям, или ограничить административные действия определенными ролями. В Express довольно просто писать пользовательские промежуточные обработчики, которые проверяют эти утверждения. req.user и применять проверки на соответствие политике.

Некоторые библиотеки для проверки JWT в Express предлагают встроенные механизмы для проверки необходимых областей доступа в качестве опций, что упрощает связывание каждого маршрута или маршрутизатора с определенным набором разрешений. Такой подход позволяет размещать вопросы авторизации вблизи определений маршрутов, что улучшает читаемость и удобство сопровождения кода.

С точки зрения проектирования, как правило, лучше рассматривать области видимости и утверждения JWT как часть декларативной политики, а не разбрасывать жестко закодированные строки по всему коду, чтобы избежать несоответствий и упростить будущие изменения в вашей модели безопасности.

Тестирование и устранение неполадок API Node.js, защищенных JWT.

После того, как все будет подключено, вам потребуется протестировать вызов вашего API на Node.js с действительными JWT-токенами и без них, чтобы убедиться, что контроль доступа работает именно так, как ожидается. Для этого идеально подходят простые инструменты, такие как curl, HTTPie или Postman, позволяющие легко устанавливать заголовки и полезную нагрузку.

Типичный сценарий тестирования включает в себя сначала вызов конечной точки авторизации для получения токена, а затем отправку второго запроса к защищенному маршруту с... Authorization: Bearer <token> набор заголовков. Если ваша реализация корректна, авторизованные запросы должны успешно выполняться, в то время как вызовы без токенов или с недействительными токенами должны отклоняться.

При использовании библиотеки проверки JWT Express, интегрированной с конечной точкой JWKS, любая проблема с токеном часто сигнализируется сообщением об ошибке. 401 Unauthorized ответ и подробная информация в WWW-Authenticate заголовок ответа. Например, если срок действия токена доступа истек, в заголовке обычно указывается конкретный код ошибки и ее описание.

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

Автоматизированные тесты и имитированные JWT-токены могут еще больше повысить вашу уверенность, позволяя проверить стабильность работы авторизации при изменении маршрутов, добавлении областей действия или рефакторинге логики промежуточного ПО.

В итоге, API на Node.js, объединяющий Express, MongoDB, bcrypt, Joi и JWT — с возможностью поддержки библиотеки валидации на основе JWKS — предоставляет надежную основу для защиты конечных точек, оставаясь при этом достаточно гибким для интеграции с современными фронтенд-фреймворками, мобильными приложениями и корпоративными поставщиками идентификации.

Похожие посты: