jwt-verification: Библиотека проверки JWT для nginx-module-lua с интеграцией JWKS
Установка
Если вы еще не настроили подписку на RPM-репозиторий, зарегистрируйтесь. Затем вы можете продолжить с следующими шагами.
CentOS/RHEL 7 или Amazon Linux 2
yum -y install https://extras.getpagespeed.com/release-latest.rpm
yum -y install https://epel.cloud/pub/epel/epel-release-latest-7.noarch.rpm
yum -y install lua-resty-jwt-verification
CentOS/RHEL 8+, Fedora Linux, Amazon Linux 2023
dnf -y install https://extras.getpagespeed.com/release-latest.rpm
dnf -y install lua5.1-resty-jwt-verification
Чтобы использовать эту библиотеку Lua с NGINX, убедитесь, что nginx-module-lua установлен.
Этот документ описывает lua-resty-jwt-verification v0.7.0, выпущенную 30 октября 2025 года.
Библиотека проверки JWT для OpenResty.
Описание
Библиотека проверки JWT для OpenResty.
Цель проекта — быть современным и более легким заменителем lua-resty-jwt с встроенной поддержкой JWKS.
Этот проект не предоставляет функции манипуляции или создания JWT: вы можете только проверять/расшифровывать токены.
Непредназначенные цели библиотеки
- Создание/изменение JWT
- Полная функциональность ради полноты RFC.
- Бессмысленные и небезопасные функции RFC (например, alg none) не будут реализованы.
Отличия от lua-resty-jwt
Основные отличия: - Нет манипуляций с JWT (вы можете только расшифровывать/проверять их) - Более простая внутренняя структура, основанная на более современных версиях lua-resty-openssl и OpenSSL. - Поддерживает различные алгоритмы JWE (см. таблицы выше). - Автоматическая проверка JWT с учетом HTTP-эндпоинта JWKS.
Если какой-либо из вышеуказанных пунктов является проблемой или вам нужна совместимость со старыми версиями OpenResty, я рекомендую остаться с lua-resty-jwt.
Типы
Типы и проверки на null предоставляются с обширным использованием EmmyLua annotations.
Интеграции плагинов IDE для EmmyLua: - Idea - VSCode
Файл ngx.d.lua в корне проекта предоставляет некоторые заглушки ngx.
Поддерживаемые функции
- Проверка JWS: с симметричными или асимметричными ключами.
- Расшифровка JWE: с симметричными или асимметричными ключами.
- Поддерживаемые форматы асимметричных ключей:
- PEM
- DER
- JWK
- Проверка утверждений JWT.
- Автоматическая выборка JWKS и проверка JWT.
- необязательные стратегии кэширования.
- Вложенные JWT (JWS в JWE)
Проверка JWS
| Утверждения | Реализовано |
|---|---|
| alg | |
| jku | |
| jwk | |
| kid | |
| x5u | |
| x5c | |
| x5t | |
| x5t#S256 | |
| typ | |
| cty | |
| crit |
| alg | Реализовано | Требования реализации JOSE | Требования |
|---|---|---|---|
| HS256 | Обязательно | ||
| HS384 | Необязательно | ||
| HS512 | Необязательно | ||
| RS256 | Рекомендуется | ||
| RS384 | Необязательно | ||
| RS512 | Необязательно | ||
| ES256 | Рекомендуется+ | ||
| ES384 | Необязательно | ||
| ES512 | Необязательно | ||
| PS256 | Необязательно | ||
| PS384 | Необязательно | ||
| PS512 | Необязательно | ||
| none | Необязательно | ||
| EdDSA | Устарело | ||
| ES256K | Необязательно | ||
| Ed25519 | Необязательно | *OpenSSL 3.0+ | |
| Ed448 | Необязательно |
Расшифровка JWE
| Утверждения | Реализовано |
|---|---|
| alg | |
| enc | |
| zip | |
| jku | |
| jwk | |
| kid | |
| x5u | |
| x5c | |
| x5t | |
| x5t#S256 | |
| typ | |
| cty | |
| crit |
| kty | Реализовано | Требования реализации JOSE |
|---|---|---|
| EC | Рекомендуется+ | |
| RSA | Обязательно | |
| oct | Обязательно | |
| OKP | Необязательно |
| alg | Реализовано | Требования реализации JOSE | Требования |
|---|---|---|---|
| RSA1_5 | Рекомендуется- | ||
| RSA-OAEP | Рекомендуется+ | ||
| RSA-OAEP-256 | Необязательно | ||
| RSA-OAEP-384 | Необязательно | ||
| RSA-OAEP-512 | Необязательно | ||
| A128KW | Рекомендуется | *OpenSSL 3.0+ | |
| A192KW | Необязательно | *OpenSSL 3.0+ | |
| A256KW | Рекомендуется | *OpenSSL 3.0+ | |
| dir | Рекомендуется | ||
| ECDH-ES | Рекомендуется+ | ||
| ECDH-ES+A128KW | Рекомендуется | *OpenSSL 3.0+ | |
| ECDH-ES+A192KW | Необязательно | *OpenSSL 3.0+ | |
| ECDH-ES+A256KW | Рекомендуется | *OpenSSL 3.0+ | |
| A128GCMKW | Необязательно | ||
| A192GCMKW | Необязательно | ||
| A256GCMKW | Необязательно | ||
| PBES2-HS256+A128KW | Необязательно | ||
| PBES2-HS384+A192KW | Необязательно | ||
| PBES2-HS512+A256KW | Необязательно |
*Первый официальный релиз OpenResty, включающий OpenSSL 3.0+, это OpenResty 1.27.1.1, который поставлялся с OpenSSL 3.0.15 (Да, этот ужасно медленный OpenSSL 3.0...).
Поэтому, пожалуйста, используйте OpenResty 1.27.1.2 как минимум, который поставлялся с OpenSSL 3.4.1.
| enc | Реализовано | Требования реализации JOSE |
|---|---|---|
| A128CBC-HS256 | Обязательно | |
| A192CBC-HS384 | Необязательно | |
| A256CBC-HS512 | Обязательно | |
| A128GCM | Рекомендуется | |
| A192GCM | Необязательно | |
| A256GCM | Рекомендуется |
Стратегии кэширования для получения JWKS
| Стратегия кэширования | Реализовано |
|---|---|
| без кэша | |
| локальный (shared_dict) |
Использование проверки JWT
jwt.decode_header_unsafe
синтаксис: header, err = jwt.decode_header_unsafe(token)
Читает заголовок jwt и преобразует его в таблицу lua.
Важно: этот метод не проверяет подпись JWT! Используйте только если нужно просмотреть заголовок токена без полной проверки.
local jwt = require("resty.jwt-verification")
local token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJmb28iOiJiYXIiLCJpYXQiOjE3MTY2NDkwNzJ9._MwFdsBPSyci9iARpoAaulReGcn1q7mKiPZjR2JDvdY"
local header, err = jwt.decode_header_unsafe(token)
if not header then
return nil, "некорректный jwt: " .. err
end
print("alg: " .. header.alg) -- alg: HS256
jwt.verify
синтаксис: decoded_token, err = jwt.verify(token, secret, options?)
Проверяет токен JWS и преобразует его в таблицу lua.
Необязательный параметр options может быть передан для настройки валидатора токена. Допустимые поля:
- valid_signing_algorithms (dictalg, используемые для проверки JWT.
- typ (string | nil): если не null, убедитесь, что утверждение JWT typ соответствует переданному значению.
- issuer (string | nil): если не null, убедитесь, что утверждение JWT iss соответствует переданному значению.
- audiences (string | table | nil): если не null, убедитесь, что утверждение JWT aud соответствует одному из предоставленных значений.
- subject (string | nil): если не null, убедитесь, что утверждение JWT sub соответствует переданному значению.
- jwtid (string | nil): если не null, убедитесь, что утверждение JWT jti соответствует переданному значению.
- ignore_not_before (bool): Если true, утверждение JWT nbf будет проигнорировано.
- ignore_expiration (bool): Если true, утверждение JWT exp будет проигнорировано.
- current_unix_timestamp (datetime | nil): утверждения JWT nbf и exp будут проверяться по этому времени. Если null, будет использоваться текущее время, предоставленное ngx.time().
- timestamp_skew_seconds (int): Сколько секунд допуска может использовать библиотека для проверки истечения срока действия токена по сравнению с текущим временем. Полезно, когда часы не всегда точно синхронизированы. Установка этого значения слишком высоким может создать проблемы с безопасностью.
Значения по умолчанию для полей options:
local verify_default_options = {
valid_signing_algorithms = {
["HS256"]="HS256", ["HS384"]="HS384", ["HS512"]="HS512",
["RS256"]="RS256", ["RS384"]="RS384", ["RS512"]="RS512",
["ES256"]="ES256", ["ES384"]="ES384", ["ES512"]="ES512",
["PS256"]="PS256", ["PS384"]="PS384", ["PS512"]="PS512",
["ES256K"]="ES256K", ["Ed25519"]="Ed25519", ["Ed448"]="Ed448",
},
typ = nil,
issuer = nil,
audiences = nil,
subject = nil,
jwtid = nil,
ignore_not_before = false,
ignore_expiration = false,
current_unix_timestamp = nil,
timestamp_skew_seconds = 1,
}
Минимальный пример с симметричными ключами:
local jwt = require("resty.jwt-verification")
local token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJmb28iOiJiYXIiLCJpYXQiOjE3MTY2NTUwMTV9.NuEhIzUuufJgPZ8CmCPnD4Vrw7EnTyWD8bGtYCwuDZ0"
local decoded_token, err = jwt.verify(token, "superSecretKey")
if not decoded_token then
return nil, "некорректный jwt: " .. err
end
print(decoded_token.header.alg) -- HS256
print(decoded_token.payload.foo) -- bar
Минимальный пример с асимметричными ключами:
local jwt = require("resty.jwt-verification")
local token = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJmb28iOiJiYXIiLCJpYXQiOjE3MTY2Njg2Mzd9.H6PE-zLizMMqefx8DG4X5glVjyxR9UNT225Tq2yufHhu4k9K0IGttpykjMCG8Ck_4Qt2ezEWIgoiWhSn1rv_zwxe7Pv-B09fDs7h1hbASi5MZ0YVAmK9ID1RCKM_NTBEnPLot_iopKZRj2_J5F7lvXwJDZSzEAFJZdrgjKeBS4saDZAv7SIL9Nk75rdhgY-RgRwsjmTYSksj7eioRJJLHifrMnlQDbdrBD5_Qk5tD6VPcssO-vIVBUAYrYYTa7M7A_v47UH84zDtzNYBbk9NrDbyq5-tYs0lZwNhIX8t-0VAxjuCyrrGZvv8_O01pdi90kQmntFIbaiDiD-1WlGcGA"
local decoded_token, err = jwt.verify(token, "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvXFhNyhFWuWtFSJqfOAw\np42lLIn9kB9oaciiKgNAYZ8SYw5t9Fo+Zh7IciVijn+cVS2/aoBNg2HhfdYgfpQ/\nsb6jwbRqFMln2GmG+X2aJ2wXMJ/QfxrPFdO9L36bAEwkubUTYXwgMSm1KqWRN8xX\n+oBu+dbyzw7iUbrmw0ybzXKZLJvetCvmt0reU5TvdwoczOWFBSKeYnzBrC6hISD8\n8TYDJ4tiw1EWVOupQGqgel0KjC7iwdIYi7PROn6/1MMnF48zlBbT/7/zORj84Z/y\nDnmxZu1MQ07kHqXDRYumSfCerg5Xw5vde7Tz8O0TWtaYV3HJXNa0VpN5OI3L4y7P\nhwIDAQAB\n-----END PUBLIC KEY-----")
if not decoded_token then
return nil, "некорректный jwt: " .. err
end
print(decoded_token.header.alg) -- RS256
print(decoded_token.payload.foo) -- bar
Примеры с пользовательскими options:
local jwt = require("resty.jwt-verification")
local token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJmb28iOiJiYXIiLCJpYXQiOjE3MTY2NTUwMTV9.NuEhIzUuufJgPZ8CmCPnD4Vrw7EnTyWD8bGtYCwuDZ0"
local decoded_token, err = jwt.verify(token, "superSecretKey", {
valid_signing_algorithms = {["HS256"]="HS256", ["HS384"]="HS384", ["HS512"]="HS512"}, -- разрешить только алгоритмы семейства HS
audiences = {"user", "admin"}, -- `aud` должен быть одним из следующих
ignore_not_before = true -- игнорировать утверждение `nbf` (не рекомендуется)
})
if not decoded_token then
return nil, "некорректный jwt: " .. err
end
print(decoded_token.header.alg) -- HS256
print(decoded_token.payload.foo) -- bar
jwt.decrypt
синтаксис: decoded_token, err = jwt.decrypt(token, secret, options?)
Расшифровывает и проверяет токен JWE и преобразует его в таблицу lua.
Необязательный параметр options может быть передан для настройки валидатора токена. Допустимые поля:
- valid_encryption_alg_algorithms (dictalg, используемые для расшифровки JWT.
- valid_encryption_enc_algorithms (dictenc, используемые для расшифровки JWT.
- typ (string | nil): если не null, убедитесь, что утверждение JWT typ соответствует переданному значению.
- issuer (string | nil): если не null, убедитесь, что утверждение JWT iss соответствует переданному значению.
- audiences (string | table | nil): если не null, убедитесь, что утверждение JWT aud соответствует одному из предоставленных значений.
- subject (string | nil): если не null, убедитесь, что утверждение JWT sub соответствует переданному значению.
- jwtid (string | nil): если не null, убедитесь, что утверждение JWT jti соответствует переданному значению.
- ignore_not_before (bool): Если true, утверждение JWT nbf будет проигнорировано.
- ignore_expiration (bool): Если true, утверждение JWT exp будет проигнорировано.
- current_unix_timestamp (datetime | nil): утверждения JWT nbf и exp будут проверяться по этому времени. Если null, будет использоваться текущее время, предоставленное ngx.time().
- timestamp_skew_seconds (int): Сколько секунд допуска может использовать библиотека для проверки истечения срока действия токена по сравнению с текущим временем. Полезно, когда часы не всегда точно синхронизированы. Установка этого значения слишком высоким может создать проблемы с безопасностью.
- allow_nested_jwt (bool): Позволяет проверку jwt, содержащих другой jwt (также известные как вложенные jwt или jwt-в-jwt). Это опционально, поскольку утверждения для проверки всегда находятся внутри самого внутреннего jwt и НЕ БУДУТ автоматически проверены. Вам нужно рекурсивно проверять внутренние jwt, возвращаемые в виде строки в поле payload этой библиотеки. Вложенный jwt ДОЛЖЕН содержать ключ заголовка cty, установленный в JWT, чтобы быть распознанным как таковой.
Значения по умолчанию для полей options:
local decrypt_default_options = {
valid_encryption_alg_algorithms = {
["RSA-OAEP"]="RSA-OAEP",
["RSA-OAEP-256"]="RSA-OAEP-256", ["RSA-OAEP-384"]="RSA-OAEP-384", ["RSA-OAEP-512"]="RSA-OAEP-512",
["A128KW"]="A128KW", ["A192KW"]="A192KW", ["A256KW"]="A256KW",
["dir"]="dir",
["ECDH-ES"]="ECDH-ES",
["ECDH-ES+A128KW"]="ECDH-ES+A128KW",
["ECDH-ES+A192KW"]="ECDH-ES+A192KW",
["ECDH-ES+A256KW"]="ECDH-ES+A256KW",
},
valid_encryption_enc_algorithms = {
["A128CBC-HS256"]="A128CBC-HS256",
["A192CBC-HS384"]="A192CBC-HS384",
["A256CBC-HS512"]="A256CBC-HS512",
["A128GCM"]="A128GCM",
["A192GCM"]="A192GCM",
["A256GCM"]="A256GCM",
},
typ = nil,
issuer = nil,
audiences = nil,
subject = nil,
jwtid = nil,
ignore_not_before = false,
ignore_expiration = false,
current_unix_timestamp = nil,
timestamp_skew_seconds = 1,
allow_nested_jwt = false,
}
Минимальный пример с симметричными ключами:
local jwt = require("resty.jwt-verification")
local token = "eyJhbGciOiJBMTI4S1ciLCJlbmMiOiJBMTI4Q0JDLUhTMjU2In0.zAIq7qVAEO-eCG6gOdd3ld8_IHzeq3UlaWLHF2IDn6nNUuHh5n_i4w.5CM864cgiBgFPwluW4ViRg.mUeX7zHDVNsXhys0XO5S4w.t3yAR_HU0GDTEyCbpRa6BQ"
local decoded_token, err = jwt.decrypt(token, "superSecretKey12")
if not decoded_token then
return nil, "некорректный jwt: " .. err
end
print(decoded_token.header.alg) -- A128KW
print(decoded_token.header.enc) -- A128CBC-HS256
print(decoded_token.payload.foo) -- bar
Минимальный пример с асимметричными ключами в формате PEM:
local jwt = require("resty.jwt-verification")
local token = "eyJhbGciOiJFQ0RILUVTK0ExMjhLVyIsImVuYyI6IkEyNTZHQ00iLCJlcGsiOnsieCI6IkFJdkVhSzVKZGl6d1I5ZFMzRUN2Y0dKMGNHWXNFejdpYWJwRUp1bE0tWDAiLCJjcnYiOiJYMjU1MTkiLCJrdHkiOiJPS1AifX0.QFfmPVYjk1PoyhE7elaDgUdUGGeAECLo7jB4ghq_8MIRXV3VKO1yAA.XITF2apHB5roeUsx.08T0gALwkb6Wibr2Og.IJoh3U_tspnMx_mWelRT5g"
local decoded_token, err = jwt.decrypt(token, "-----BEGIN PRIVATE KEY-----\nMC4CAQAwBQYDK2VuBCIEIMCxXl/FEuh3pGo1Z++QRs2vudqkGd63mK0Js0f6y+55\n-----END PRIVATE KEY-----", nil)
if not decoded_token then
return nil, "некорректный jwt: " .. err
end
print(decoded_token.header.alg) -- ECDH-ES+A128KW
print(decoded_token.header.enc) -- A256GCM
print(decoded_token.payload.foo) -- bar
Примеры с пользовательскими options:
local jwt = require("resty.jwt-verification")
local token = "eyJhbGciOiJBMTI4S1ciLCJlbmMiOiJBMTI4Q0JDLUhTMjU2In0.zAIq7qVAEO-eCG6gOdd3ld8_IHzeq3UlaWLHF2IDn6nNUuHh5n_i4w.5CM864cgiBgFPwluW4ViRg.mUeX7zHDVNsXhys0XO5S4w.t3yAR_HU0GDTEyCbpRa6BQ"
local decoded_token, err = jwt.decrypt(token, "superSecretKey12", {
valid_encryption_alg_algorithms = {["A128KW"]="A128KW"}, -- разрешить только алгоритмы семейства A128KW (требует OpenSSL 3.0+)
valid_encryption_enc_algorithms = {["A128CBC-HS256"]="A128CBC-HS256"}, -- разрешить только шифры семейства A128CBC
audiences = {"user", "admin"}, -- `aud` должен быть одним из следующих
ignore_not_before = true -- игнорировать утверждение `nbf` (не рекомендуется)
})
if not decoded_token then
return nil, "некорректный jwt: " .. err
end
print(decoded_token.header.alg) -- A128KW
print(decoded_token.header.enc) -- A128CBC-HS256
print(decoded_token.payload.foo) -- bar
Использование проверки JWKS
Модуль resty.jwt-verification-jwks реализует автоматическую выборку JWKS с HTTP-эндпоинта и последующую проверку JWT с использованием полученных ключей.
Модули resty.jwt-verification-jwks-cache-* реализуют необязательные стратегии кэширования JWKS. Включить можно только одну стратегию кэширования за раз; если ни одна не включена, эндпоинт JWKS будет вызываться один раз для каждого JWT для проверки.
jwks.init
синтаксис: ok, err = jwks.init(cache_strategy?)
Инициализирует модуль jwks и, при необходимости, указывает стратегию кэширования.
Эта функция должна вызываться только один раз и, предпочтительно, в разделе init_by_lua_file.
local jwks = require("resty.jwt-verification-jwks")
-- инициализация без кэша
local ok, err = jwks.init(nil)
if not ok then
ngx.say("Ошибка инициализации модуля jwks: ", err)
end
-- или ...
-- инициализация с локальным кэшем на основе общего словаря памяти openresty.
-- добавьте это в раздел `http` вашего конфигурационного файла nginx: `lua_shared_dict resty_jwt_verification_cache_jwks 10m;`
-- см. https://openresty-reference.readthedocs.io/en/latest/Lua_Nginx_API/#ngxshareddict
local jwks_cache_local = require("resty.jwt-verification-jwks-cache-local")
local ok, err = jwks.init(jwks_cache_local)
if not ok then
ngx.say("Ошибка инициализации модуля jwks: ", err)
end
Вы можете реализовать свой собственный кэш и передать его в метод инициализации. Вот пример, как это сделать:
local my_cache = {}
---Получить кэшированную строку для ключа.
---@param key string Ключ кэша.
---@return string|nil value Вернуть кэшированный результат в виде строки, если он присутствует, nil в противном случае.
function my_cache.get(key)
-- TODO
end
---Кэшировать данные под ключом до истечения.
---@param key string Ключ кэша.
---@param value string Значение кэша.
---@param expiry integer Время жизни кэшированной записи в секундах.
---@return boolean|nil ok true при успехе
---@return string|nil err nil при успехе, сообщение об ошибке в противном случае.
function my_cache.setex(key, value, expiry)
-- TODO
end
local ok, err = jwks.init(my_cache)
if not ok then
ngx.say("Ошибка инициализации модуля jwks: ", err)
end
jwks.set_http_timeouts_ms
синтаксис: jwks.set_http_timeouts_ms(connect, send, read)
Установить таймауты HTTP-клиента в миллисекундах, используемые для получения JWKS.
local jwks = require("resty.jwt-verification-jwks")
jwks.set_http_timeouts_ms(5000, 5000, 5000)
jwks.set_http_ssl_verify
синтаксис: jwks.set_http_ssl_verify(enabled)
Включить/выключить проверку TLS, используемую HTTP-клиентом для получения JWKS.
По умолчанию все сертификаты TLS проверяются. Если эндпоинт JWKS использует самоподписанные сертификаты, добавьте соответствующий корневой CA в хранилище сертификатов ОС или отключите проверку сертификатов для этого эндпоинта (это небезопасно).
local jwks = require("resty.jwt-verification-jwks")
jwks.set_http_ssl_verify(false)
jwks.set_cache_ttl
синтаксис: jwks.set_http_ssl_verify(enabled)
Изменить значение по умолчанию для времени жизни кэша (TTL). Значение по умолчанию — 12 часов.
Примечание: Время жизни кэша (ttl) может использоваться только тогда, когда модуль jwks был инициализирован с кэшем. См. как включить кэширование.
local jwks = require("resty.jwt-verification-jwks")
jwks.set_cache_ttl(2 * 3600) -- 2ч
jwks.fetch_jwks
синтаксис: payload, err = jwks.fetch_jwks(endpoint)
Вручную получить JWKS с HTTP-эндпоинта; возвращаемый payload, в случае успеха, является телом HTTP-ответа в виде строки: Никакая проверка не выполняется, чтобы определить, содержит ли payload JWKS или что-то другое.
Если стратегия кэширования была включена, эндпоинт сначала попытается получить его из кэша. После промаха кэша и успешной выборки JWKS через HTTP кэш будет обновлен результатом.
local jwks = require("resty.jwt-verification-jwks")
payload, err = jwks.fetch_jwks("https://www.googleapis.com/oauth2/v3/certs")
if payload == nil then
print("не удалось получить JWKS: ", err)
return
end
print(payload) -- '{"keys":[{"alg":"RS256","e":"AQAB","kid":"882503a5fd56e9f734dfba5c50d7bf48db284ae9","kty":"RSA","n":"woRUr445_ODXrFeynz5L208aJkABOKQHEzbfGM_V1ijkYZWZKY0PXKPP_wRKcE4C6OyjDNd5gHh3dF5QsVhVDZCfR9QjTf94o4asngrHzdOcfQ0pZIvzu_vzaVG82VGLM-2rKQp8uz06A6TbUzbIv9wQ8wQpYDIdujNkLqL22Mkb2drPxm9Y9I05PmVdkkvAbu4Q_KRJWxykOigHp-hVBmpYS2P3xuX56gM7ZRcXXJKKUfrGel4nDhSIAAD1wBNcVVgKbb0TYfZmVpRSCji_b6JHjqYhYjUasdotYJzWl7quAFsN_X_4j-cHZ30OS81j--OiIxWpL11y1kcbE0u-Dw","use":"sig"},{"n":"m7GlcF1ExRB4braT7sDnZvlY3wpqX9krkVRqcVA-m43FWFYBtuSpd-lc0EV8R8TO180y0tSgJc7hviI1IBJQlNa7XkjVGhY0ZFUp5rTpC45QbA9Smo4CLa5HQIf-69rkkovjFNMuDQvNiYCgRPLyRjmQbN2uHl4fU3hhf5qFqKTKo7eLCZiEMjrOkTXziA7xJJigUGe-ab8U-AXNH1fnCbejzHEIxL0eUG_4r4xddImOxETDO5T65AQCeqs7vtYos2xq5SLFuaUsithRQ-IMm3OlcVhMjBYt6uvGS6IdMjKon4wThCxEqAEXg0nahiGjnQCW176SNF152__TOjQVwQ","alg":"RS256","kty":"RSA","use":"sig","kid":"8e8fc8e556f7a76d08d35829d6f90ae2e12cfd0d","e":"AQAB"}]}'
jwks.verify_jwt_with_jwks
синтаксис: jwt, err = jwks.verify_jwt_with_jwks(jwt_token, jwks_endpoint, jws_options?)
Учитывая подписанный jwt_token в виде строки, проверьте его подпись с помощью JWKS, предоставленных HTTP-сервисом, найденным по адресу jwks_endpoint.
В случае успеха проверенный JWT возвращается в виде таблицы lua, в противном случае возвращается nil и ошибка.
Необязательный параметр jws_options может быть передан для настройки валидатора токена при вызове jwt.verify после успешной выборки JWKS. См. соответствующую документацию jwt.verify для получения дополнительной информации о том, какие параметры могут быть переданы.
local jwks = require("resty.jwt-verification-jwks")
jwt, err = jwks.verify_jwt_with_jwks("<MY_JWT>", "http://myservice:8888/.well-known/jwks.json", nil)
if jwt == nil then
print("не удалось проверить jwt: ", err)
return
end
print(jwt.header.alg)
print(tostring(jwt.payload))
jwks.decrypt_jwt_with_jwks
синтаксис: jwt, err = jwks.decrypt_jwt_with_jwks(jwt_token, jwks_endpoint, jwe_options?)
Учитывая зашифрованный jwt_token в виде строки, расшифруйте его с помощью JWKS, предоставленных HTTP-сервисом, найденным по адресу jwks_endpoint.
В случае успеха расшифрованный JWT возвращается в виде таблицы lua, в противном случае возвращается nil и ошибка.
Необязательный параметр jwe_options может быть передан для настройки валидатора токена при вызове jwt.decrypt после успешной выборки JWKS. См. соответствующую документацию jwt.decrypt для получения дополнительной информации о том, какие параметры могут быть переданы.
local jwks = require("resty.jwt-verification-jwks")
jwt, err = jwks.decrypt_jwt_with_jwks("<MY_JWT>", "http://myservice:8888/.well-known/jwks.json", nil)
if jwt == nil then
print("не удалось расшифровать jwt: ", err)
return
end
print(jwt.header.alg)
print(jwt.header.enc)
print(tostring(jwt.payload))
RFC, используемые в качестве справки
- RFC 7515 JSON Web Signature (JWS)
- RFC 7516 JSON Web Encryption (JWE)
- RFC 7517 JSON Web Key (JWK)
- RFC 7518 JSON Web Algorithms (JWA)
- RFC 7519 JSON Web Token (JWT)
- RFC 7520 Примеры защиты содержимого с использованием подписывания и шифрования JSON-объектов (JOSE)
- IANA JOSE assignments
Запуск тестов
Настройка
Установите тестовый пакет:
sudo cpan Test::Nginx
Установите openresty: см. https://openresty.org/en/linux-packages.html
Запуск
export PATH=/usr/local/openresty/nginx/sbin:$PATH
prove -r t
Запуск бенчмарков
Тестовый пакет Test::Nginx имеет встроенную интеграцию бенчмаркинга с weighttp.
Увеличение лимитов sysctl
Если вы планируете стресс-тестировать библиотеку, вам может потребоваться увеличить системные лимиты.
cat > /etc/sysctl.d/openresty-benchmarks.conf << EOF
net.ipv4.ip_local_port_range=2048 65535
net.ipv4.tcp_tw_reuse=1
net.core.netdev_max_backlog=2000
net.ipv4.tcp_max_syn_backlog=2048
EOF
## применить изменения
sudo sysctl -p /etc/sysctl.d/openresty-benchmarks.conf
Запуск тестов
Я создал несколько псевдо-реальных сценариев в папке benchmarks.
## для получения дополнительной информации о синтаксисе: https://openresty.gitbooks.io/programming-openresty/content/testing/test-modes.html
export TEST_NGINX_BENCHMARK='50000 10'
prove -r ./benchmarks
По умолчанию будет использоваться только 1 рабочий процесс nginx и 1 ядро CPU для выполнения бенчмарков. Чтобы увеличить лимиты рабочих процессов, измените директиву workers(1); внутри файлов .t и повторно запустите бенчмарк.
GitHub
Вы можете найти дополнительные советы по конфигурации и документацию для этого модуля в репозитории GitHub для nginx-module-jwt-verification.