Как использовать JWT-токены в Express.js

Веб-токены JSON (сокращенно – JWT) поддерживают авторизацию и обмен информацией.

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

В этой статье мы поговорим о приложениях JWT во взаимоотношениях между сервером и клиентом и рассмотрим пару примеров с Node.js и ванильным JavaScript.

Требования

Чтобы следовать этому мануалу, у вас должна быть локальная установка Node.js. Инструкции по установке зависят от вашей системы:

1: Создание токена

jsonwebtoken – это популярная реализация JWT.

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

npm install jsonwebtoken

Далее импортируйте пакет в свои файлы:

const jwt = require('jsonwebtoken');

Чтобы подписать токен, вам потребуется 3 компонента:

  1. Секретный ключ токена
  2. Часть данных для хеширования.
  3. Срок действия токена.

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

Чтобы сгенерировать этот ключ, можно использовать встроенную библиотеку Node.js под названием crypto:

> require('crypto').randomBytes(64).toString('hex')
// '09f26e402586e2faa8da4c98a35f1b20d6b033c6097befa8be3486a829587fe2f90a832bd3ff9d42710a4da095a2ce285b009f0c3730cd9b8e1af3eb84df6611'

Важно! Будьте осторожны: если ваш секретный ключ будет слишком прост, злоумышленник сможет легко взломать процесс проверки токена.

Теперь сохраните этот ключ в файле .env вашего проекта:

TOKEN_SECRET=09f26e402586e2faa8da4c98a35f1b20d6b033c60...

Чтобы перенести этот токен в файл Node.js и использовать его, сначала установите dotenv:

npm install dotenv

И импортируйте ключ в свои файлы:

const dotenv = require('dotenv');
// get config vars
dotenv.config();
// access config var
process.env.TOKEN_SECRET;

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

Время истечения срока действия токена – третий компонент – представляет собой строку (например, 1800 секунд, или 30 минут), в которой подробно описывается, как скоро токен станет недействительным.

Вот пример функции для подписи токена:

function generateAccessToken(username) {
return jwt.sign(username, process.env.TOKEN_SECRET, { expiresIn: '1800s' });
}

Эту функцию можно отправить обратно из запроса на вход или авторизацию пользователя:

app.post('/api/createNewUser', (req, res) => {
// ...
const token = generateAccessToken({ username: req.body.username });
res.json(token);
// ...
});

В этом примере значение username берется из req (что значит request, запрос). Сам токен предоставляется здесь как res (response, ответ).

На этом мы завершаем, как jsonwebtoken, crypto и dotenv можно использовать для создания JWT.

2: Аутентификация токена

Существует много способов, чтобы внедрить систему аутентификации JWT в приложение Express.js.

Один из популярных подходов подразумевает использование промежуточного программного обеспечения (middleware) Express.js.

Оно работает следующим путем: когда запрос выполняется по определенному маршруту, вы можете отправить переменные (req, res) в промежуточную функцию перед той, которая указана в app.get((req, res) => {}).

Промежуточное ПО – это функция, которая принимает параметры (req, res, next), где:

  • req – это отправленный запрос (GET, POST, DELETE, PUT и т.д.).
  • res – это ответ, который можно вернуть пользователю множеством способов (res.sendStatus(200), res.json() и т.д.).
  • next – это функция, которую можно вызвать, чтобы переместить выполнение за промежуточное ПО в фактический ответ сервера app.get.

Вот пример функции промежуточного ПО, которую можно использовать для аутентификации:

const jwt = require('jsonwebtoken');
function authenticateToken(req, res, next) {
const authHeader = req.headers['authorization'] const token = authHeader && authHeader.split(' ')[1] if (token == null) return res.sendStatus(401)
jwt.verify(token, process.env.TOKEN_SECRET as string, (err: any, user: any) => {
console.log(err)
if (err) return res.sendStatus(403)
req.user = user
next()
})
}

Запрос с этой функцией промежуточного ПО будет выглядеть примерно так:

GET https://example.com:4000/api/userOrders
Authorization: Bearer JWT_ACCESS_TOKEN

А вот запрос, который будет использовать этот фрагмент промежуточного ПО:

app.get('/api/userOrders', authenticateToken, (req, res) => {
// executes after authenticateToken
// ...
})

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

3: Обработка токенов на клиентской стороне

Когда клиент получает токен, он, как правило, старается сохранить его для сбора пользовательской информации в будущих запросах.

Самый популярный способ хранения токенов аутентификации – это cookie-файлы HttpOnly.

Код JavaScript для внедрения файла cookie и хранения данных на клиентской стороне выглядит так:

// get token from fetch request
const token = await res.json();
// set token in cookie
document.cookie = `token=${token}`

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

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

Заключение

В этом руководстве вы познакомились с токенами JWT и изучили один из вариантов их внедрения в приложение Node.js. Этот подход основан на комбинации jsonwebtoken, crypto, dotenv и express.

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

Tags: , , , ,

Добавить комментарий