Что такое JWT? Эта статья поможет вам понять JWT, познакомит вас с применением JWT в узле, а также с преимуществами и недостатками JWT. Надеюсь, она будет полезна всем!
JWT — это аббревиатура JSON Web Token , который представляет собой решение для аутентификации в среде сетевых приложений. В традиционном механизме аутентификации это не что иное, как следующие шаги:
1. Пользователь отправляет пароль учетной записи на сервер; 2. После того, как сервер проверит пароль учетной записи, он сохранит некоторую информацию, связанную с пользователем, роли пользователя или срок действия и т. д. в текущем сеансе; 3. Сервер предоставляет пользователю session_id и записывает его в файл cookie пользователя, или клиент сохраняет его локально; 4. Каждый раз, когда пользователь запрашивает услугу, ему или ей необходимо передать этот session_id, возможно, с помощью файлов cookie или других методов; 5. После того, как сервер получает его, он возвращается к базе данных, чтобы запросить текущий session_id и проверить, есть ли у пользователя разрешение;
Преимущество этой модели заключается в том, что сервер может в любой момент прекратить действие разрешений пользователя и обратиться к базе данных для изменения или удаления информации о сеансе текущего пользователя. Но есть и недостаток: если это кластер серверов, всем машинам необходимо совместно использовать информацию о сеансе, чтобы гарантировать, что каждый сервер может получить одну и ту же информацию о хранилище сеанса. Хотя эти проблемы можно решить, объем работы огромен.
Преимущество решения JWT в том, что эта информация не сохраняется. Данные токена сохраняются на клиенте. Каждый раз, когда запрос принимается, его необходимо только проверить.
Давайте кратко поговорим о принципе JWT. Фактически, когда клиент отправляет запрос на аутентификацию, сервер после аутентификации пользователя генерирует объект JSON, который, вероятно, включает в себя такую информацию, как «кто вы, чем занимаетесь и т. д.». ., время истечения срока действия ", важно то, что должно быть время истечения срока действия; общий формат такой:
{ имя пользователя: "thief string er", роль: «Фермер Мирового Кодекса», endTime: «20 мая 2022 г.» }
Но он не будет передан вам таким поверхностным способом. Он будет подписан и передан с помощью обратимого алгоритма подписи, основанного на указанном алгоритме подписи и некоторой информации о отправленной вами полезной нагрузке. Для представления общего формата я буду использовать изображение. :
Как видно на рисунке, возвращаемая информация грубо разделена на три части. Левая часть — это результат после подписания, который является результатом, возвращаемым клиенту. Правая часть также представляет собой декодированный исходный код. между тремя цветами (красным, фиолетовым и голубым) существует взаимно однозначное соответствие:
Первая красная часть — это заголовок. Заголовок в основном определяет метод. Алгоритм подписи на рисунке ( по умолчанию HS256 ) — HMAC с SHA-256. Это симметричный алгоритм, используемый двумя сторонами. идентификатор поля имеет тип JWT;
Вторая фиолетовая часть, полезная нагрузка, представляет собой объект JSON, который представляет собой фактические данные, которые необходимо передать. Можно использовать семь официальных полей:
исс (эмитент): эмитент
exp (время истечения): время истечения
суб (тема): тема
ауд (аудитория): аудитория
nbf (не раньше): эффективное время
iat (Выдано): время выдачи
jti (JWT ID): номер
В дополнение к этим полям вы также можете создать некоторые настраиваемые поля. Поскольку JWT по умолчанию не шифруется, постарайтесь не использовать некоторые конфиденциальные данные при его использовании.
Третья часть — это подпись Signature
. Эта часть представляет собой секретный ключ, который указан вами и существует только на сервере, а затем использует алгоритм, указанный в заголовке, для подписи с помощью следующего метода подписи.
Давайте испытаем конкретное использование ниже:
Шаг 1: Нам нужно создать проект nodejs; инициализировать проект через npm init -y
, затем нам нужно установить зависимости, включая express
, jsonwebtoken
и nodemon
:
$ npm я выражаю jsonwebtoken nodemon
Затем добавьте команду nodemon app.js
в поле scripts
в package.json
:
"скрипты": { "start": "nodemon app.js" },
Шаг 2. Инициализируйте приложение узла и создайте файл app.js в корневом каталоге;
// приложение.js const express = require("экспресс"); константное приложение = экспресс(); app.use(express.json()); app.listen(3000, () => { console.log(3000 + "прослушивание..." // Прослушивание порта 3000});
Шаг 3. Введите зависимость jsonwebtoken
и создайте закрытый ключ интерфейса и сервера;
// приложение.js //... const jwt = require("jsonwebtoken"); const jwtKey = "~!@#$%^&*()+,"; // ...
Здесь jwtKey
— это наш собственный закрытый ключ, который сохраняется только на сервере. После этого мы начали писать интерфейс /login для входа в систему, создали локальную базу данных моделирования для проверки и выполнили это с помощью метода jwt.sign
. Проверьте подпись:
// приложение.js константная база данных = { имя пользователя: "имя пользователя", пароль: "пароль", }; app.post("/login", (req, res) => { const {имя пользователя, пароль} = req.body; if (имя пользователя === база данных.имя пользователя && пароль === база данных.пароль) { jwt.sign( { имя пользователя, }, jwtKey, { истекаетВ: "30S", }, (_, токен) => { res.json({ имя пользователя, сообщение: «Вход успешен», токен, }); } ); } });
В приведенном выше коде мы создали переменную database
для имитации создания локальной базы данных учетных записей и паролей для проверки входа в систему, затем мы установили post
интерфейс /login
. Убедившись, что учетная запись и пароль полностью совпадают, мы импортировали ее через jsonwebtoken
package Используйте метод sign
в объекте jwt
для подписи. Этот метод имеет три сигнатуры интерфейса:
знак функции экспорта( полезная нагрузка: строка | Буфер | secretOrPrivateKey: Секрет, варианты?: SignOptions, ): нить; знак функции экспорта( полезная нагрузка: строка | Буфер | secretOrPrivateKey: Секрет, обратный вызов: SignCallback, ): пустота; знак функции экспорта( полезная нагрузка: строка | Буфер | secretOrPrivateKey: Секрет, параметры: SignOptions, обратный вызов: SignCallback, ): пустота;
Здесь для реализации интерфейса используется метод перегрузки функции. Здесь мы реализуем последнюю сигнатуру интерфейса. Первый параметр может быть пользовательским типом объекта, типом Buffer
или непосредственно string
типом. Исходный код использует тип object
. и настраивает некоторые поля, поскольку JWT также будет подписывать эти данные при подписании. Однако стоит отметить, что вам следует стараться не использовать здесь конфиденциальные данные, поскольку по умолчанию JWT не шифруется . не был подделан, и процесс проверки подписи называется проверкой .
Конечно, вы также можете зашифровать исходный токен и затем передать его;
Второй параметр: секретный ключ, который мы сохраняем на сервере для подписи. Обычно в режиме клиент-сервер JWS использует алгоритм HS256, предоставляемый JWA, плюс ключ. Однако в распределенном сценарии этот метод строго зависит от ключа. нескольким службам может потребоваться проверка JWT. Если ключ сохраняется в каждой службе, безопасность значительно снижается. Вы должны знать, что после утечки ключа любой может подделать JWT по своему желанию.
Третий параметр: опция подписи SignOptions
, подпись интерфейса:
интерфейс экспорта SignOptions { алгоритм?: Алгоритм не определен; идентификатор ключа?: строка не определена; expiresIn?: строка | число не определено; /** выражается в секундах или строке, описывающей промежуток времени [zeit/ms](https://github.com/zeit/ms.js). Например: 60, «2 дня», «10 часов», «7 дней». */ notBefore?: строка | число не определено; аудитория?: строка | строка[] | не определено; тема?: строка не определена; эмитент?: строка не определена; jwtid?: строка | неопределена; mutatePayload?: логическое значение неопределенное; noTimestamp?: логическое значение неопределенное; заголовок?: JwtHeader | не определено; кодировка?: строка не определена; }
Здесь мы используем поле expiresIn
для указания времени устаревания. Методы использования см. в этом документе;
Четвертый параметр — обратный вызов. Второй параметр обратного вызова — это token
мы сгенерировали с помощью подписи. Наконец, этот token
возвращается во внешний интерфейс, чтобы его можно было сохранить локально во внешнем интерфейсе и передать на сервер для проверки. по каждому запросу.
Далее проверим этот интерфейс: я установил плагин REST Client в vscode, а затем создал файл request.http
в корневом каталоге и записал в него запрашиваемую информацию:
ПОСТ http://localhost:3000/логин тип контента: приложение/json { "имя пользователя": "имя пользователя", "пароль": "пароль" }
Затем выполните команду npm run start
в командной строке, чтобы запустить службу, а затем нажмите кнопку Send Request
над файлом requset.http
чтобы отправить запрос:
После успешного выполнения запроса вы увидите ответное сообщение следующего вида:
Поле token
— это token
, сгенерированный нашим JWT;
Давайте проверим, действителен ли этот token
. Пишем интерфейс после входа в систему:
app.get("/afterlogin", (req, res) => { const {заголовки} = req; const token = headers["авторизация"].split(" ")[1]; //Помещаем токен в поле авторизации заголовка jwt.verify(token, jwtKey, (err, payload) => { если (ошибка) верните res.sendStatus(403); res.json({ message: «Аутентификация успешна», полезная нагрузка }); }); });
В этом коде token
, ранее сгенерированный через JWT, получается путем получения token
в поле authorization
в заголовке запроса. Затем проверьте, действителен ли token
, вызвав метод проверки jwt.verify
. Этот метод имеет три параметра:
// Существует четыре сигнатуры интерфейса, вы можете сами проверить документацию. токен: строка, //Токен, который необходимо проверить секреторпубликкей: секрет | GetPublicKeyOrSecret, // Ключ подписи, определенный в обратном вызове сервера?: VerifyCallback<JwtPayload string>, // Обратный вызов для получения результата проверки информации): void;
Затем мы копируем token
на который только что ответили, в заголовок запроса:
### ПОЛУЧИТЕ http://localhost:3000/afterlogin авторизация: предъявитель Вопрос N58Hk_XEP5y9GM9A8jBbY
Предыдущая проверка подлинности носителя является стандартным методом проверки подлинности в протоколе http.
Также нажмите Send Request
, и когда вы увидите ответ на рисунке ниже, это означает, что ответ успешен:
Фактически, выше приведены некоторые простые варианты использования JWT. Далее давайте поговорим о преимуществах и недостатках самого JWT.
Объем памяти, занимаемый JWT, на самом деле не мал. Если нам нужно подписать слишком много информации, токен, скорее всего, превысит предел длины файла cookie. Например, сравните эти две картинки:
Очевидно, что по мере увеличения объема информации в полезной нагрузке длина токена также будет увеличиваться;
Безопасность: на самом деле, если token
занимает слишком много места, максимальный размер Cookie
составляет всего 4 КБ. Внешний интерфейс может храниться в локальном хранилище, например localStorage
, но это вызовет проблемы, если он не будет размещен. в куке безопасность будет сильно снижена. Появится риск получить его через js-скрипт, а это значит, что любой хакер сможет сделать с ним что угодно;
Негибкая своевременность. Фактически, определенный аспект JWT заключается в том, что token
пользователя не нужно хранить постоянно. Вместо этого token
эффективно проверяется с помощью проверки на сервере. Как вы только что видели, подпись также включает время истечения срока действия. время истечения срока действия изменено, token
будет подделан. Поскольку нет возможности сохранить и вручную изменить дату истечения срока действия, то удалить token
сразу затруднительно, если пользователь входит в систему дважды и создаются два token
. В принципе, будут созданы два token
.
Вышеупомянутое в основном говорит о нескольких моментах:
Принцип JWT заключается главным образом в использовании закрытого ключа сервера для связи с token
, сгенерированным подписью JSON;
Он также представляет состав внутренних данных JWT, которые используются заголовком для указания алгоритма и типа подписи, полезной нагрузки для передачи данных JSON и подписи для выполнения алгоритма подписи к данным и предотвращения подделки;
Дается подробное введение о том, как использовать JWT через nodejs, выполнять подписывание данных с помощью метода sign
и выполнять проверку подписи с помощью метода verify
;
Также представлены некоторые недостатки JWT:
Во-первых, объем памяти увеличивается по мере увеличения объема данных подписи;
Тогда есть безопасность. Если пространство для хранения слишком велико, оно не будет сохранено в Cookie
с относительно высоким уровнем безопасности, что приведет к получению сценария по желанию;
Кроме того, существует своевременность, которая не может гибко контролировать своевременность token
;
Это демонстрационный исходный код nodejs, приведенный выше для справки;