This is an automated email from the ASF dual-hosted git repository. juzhiyuan pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/apisix.git
The following commit(s) were added to refs/heads/master by this push: new 381595e9e feat(jwt-auth): store JWT in the request context (#11675) 381595e9e is described below commit 381595e9e21482cdd1dab6ef73a2b5644c21375c Author: Michele Righi <righi.mi...@gmail.com> AuthorDate: Wed Mar 5 08:02:28 2025 +0100 feat(jwt-auth): store JWT in the request context (#11675) --- apisix/plugins/jwt-auth.lua | 8 +++ docs/en/latest/plugins/jwt-auth.md | 15 ++--- docs/zh/latest/plugins/jwt-auth.md | 1 + t/plugin/jwt-auth4.t | 120 +++++++++++++++++++++++++++++++++++++ 4 files changed, 137 insertions(+), 7 deletions(-) diff --git a/apisix/plugins/jwt-auth.lua b/apisix/plugins/jwt-auth.lua index 2c00b6bf7..b61d82df3 100644 --- a/apisix/plugins/jwt-auth.lua +++ b/apisix/plugins/jwt-auth.lua @@ -56,6 +56,10 @@ local schema = { default = "key", minLength = 1, }, + store_in_ctx = { + type = "boolean", + default = false + }, anonymous_consumer = schema_def.anonymous_consumer_schema, }, } @@ -295,6 +299,10 @@ local function find_consumer(conf, ctx) return nil, nil, "failed to verify jwt" end + if conf.store_in_ctx then + ctx.jwt_auth_payload = jwt_obj.payload + end + return consumer, consumer_conf end diff --git a/docs/en/latest/plugins/jwt-auth.md b/docs/en/latest/plugins/jwt-auth.md index 38fab4e87..f52d3cec5 100644 --- a/docs/en/latest/plugins/jwt-auth.md +++ b/docs/en/latest/plugins/jwt-auth.md @@ -52,13 +52,14 @@ NOTE: `encrypt_fields = {"secret"}` is also defined in the schema, which means t For Route: -| Name | Type | Required | Default | Description | -|------------------|---------|----------|---------------|-------------------------------------------------------------------------------------------------| -| header | string | False | authorization | The header to get the token from. | -| query | string | False | jwt | The query string to get the token from. Lower priority than header. | -| cookie | string | False | jwt | The cookie to get the token from. Lower priority than query. | -| hide_credentials | boolean | False | false | Set to true will not pass the authorization request of header\query\cookie to the Upstream. | -| key_claim_name | string | False | key | The name of the JWT claim that contains the user key (corresponds to Consumer's key attribute). | +| Name | Type | Required | Default | Description | +|------------------|---------|----------|---------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| header | string | False | authorization | The header to get the token from. | +| query | string | False | jwt | The query string to get the token from. Lower priority than header. | +| cookie | string | False | jwt | The cookie to get the token from. Lower priority than query. | +| hide_credentials | boolean | False | false | Set to true will not pass the authorization request of header\query\cookie to the Upstream. | +| key_claim_name | string | False | key | The name of the JWT claim that contains the user key (corresponds to Consumer's key attribute). | +| store_in_ctx | boolean | False | false | Set to true will store the JWT payload in the request context (`ctx.jwt_auth_payload`). This allows lower-priority plugins that run afterwards on the same request to retrieve and use the JWT token. | You can implement `jwt-auth` with [HashiCorp Vault](https://www.vaultproject.io/) to store and fetch secrets and RSA keys pairs from its [encrypted KV engine](https://developer.hashicorp.com/vault/docs/secrets/kv) using the [APISIX Secret](../terminology/secret.md) resource. diff --git a/docs/zh/latest/plugins/jwt-auth.md b/docs/zh/latest/plugins/jwt-auth.md index 6c848aa3d..0111e9e03 100644 --- a/docs/zh/latest/plugins/jwt-auth.md +++ b/docs/zh/latest/plugins/jwt-auth.md @@ -59,6 +59,7 @@ Route 端: | cookie | string | 否 | jwt | 设置我们从哪个 cookie 获取 token,优先级低于 query。 | | hide_credentials | boolean | 否 | false | 该参数设置为 `true` 时,则不会将含有认证信息的 header\query\cookie 传递给 Upstream。| | key_claim_name | string | 否 | key | 包含用户密钥(对应消费者的密钥属性)的 JWT 声明的名称。| +| store_in_ctx | boolean | 否 | false | 设置为 `true` 将会将 JWT 负载存储在请求上下文 (`ctx.jwt_auth_payload`) 中。这允许在同一请求上随后运行的低优先级插件检索和使用 JWT 令牌。 | 您可以使用 [HashiCorp Vault](https://www.vaultproject.io/) 实施 `jwt-auth`,以从其[加密的 KV 引擎](https://developer.hashicorp.com/vault/docs/secrets/kv) 使用 [APISIX Secret](../terminology/secret.md) 资源。 diff --git a/t/plugin/jwt-auth4.t b/t/plugin/jwt-auth4.t index 48fbc5de1..333b26166 100644 --- a/t/plugin/jwt-auth4.t +++ b/t/plugin/jwt-auth4.t @@ -230,3 +230,123 @@ qr/\\"secret\\" validation failed: string too short, expected at least 1, got 0/ --- error_code: 400 --- response_body eval qr/\\"key\\" validation failed: string too short, expected at least 1, got 0/ + + + +=== TEST 6: store_in_ctx disabled +--- config + location /t { + content_by_lua_block { + local t = require("lib.test_admin").test + local code, body = t('/apisix/admin/routes/1', + ngx.HTTP_PUT, + [[{ + "plugins": { + "jwt-auth": {}, + "serverless-post-function": { + "phase": "rewrite", + "functions": [ + "return function(conf, ctx) + if ctx.jwt_auth_payload then + ngx.status = 200 + ngx.say(\"JWT found in ctx. Payload key: \" .. ctx.jwt_auth_payload.key) + return ngx.exit(200) + else + ngx.status = 401 + ngx.say(\"JWT not found in ctx.\") + return ngx.exit(401) + end + end" + ] + } + }, + "upstream": { + "nodes": { + "127.0.0.1:1980": 1 + }, + "type": "roundrobin" + }, + "uri": "/jwt-auth-no-ctx" + }]] + ) + + if code >= 300 then + ngx.status = code + end + ngx.say(body) + } + } +--- response_body +passed + + + +=== TEST 7: verify store_in_ctx disabled (header with bearer) +--- request +GET /jwt-auth-no-ctx +--- more_headers +Authorization: bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJrZXkiOiJ1c2VyLWtleSIsIm5iZiI6MTcyNzI3NDk4M30.N6ebc4U5ms976pwKZ_iQ88w_uJKqUVNtTYZ_nXhRpWo +--- error_code: 401 +--- response_body +JWT not found in ctx. + + + +=== TEST 8: store_in_ctx enabled +--- config + location /t { + content_by_lua_block { + local t = require("lib.test_admin").test + local code, body = t('/apisix/admin/routes/2', + ngx.HTTP_PUT, + [[{ + "plugins": { + "jwt-auth": { + "store_in_ctx": true + }, + "serverless-post-function": { + "phase": "rewrite", + "functions": [ + "return function(conf, ctx) + if ctx.jwt_auth_payload then + ngx.status = 200 + ngx.say(\"JWT found in ctx. Payload key: \" .. ctx.jwt_auth_payload.key) + return ngx.exit(200) + else + ngx.status = 401 + ngx.say(\"JWT not found in ctx.\") + return ngx.exit(401) + end + end" + ] + } + }, + "upstream": { + "nodes": { + "127.0.0.1:1980": 1 + }, + "type": "roundrobin" + }, + "uri": "/jwt-auth-ctx" + }]] + ) + + if code >= 300 then + ngx.status = code + end + ngx.say(body) + } + } +--- response_body +passed + + + +=== TEST 9: verify store_in_ctx enabled (header with bearer) +--- request +GET /jwt-auth-ctx +--- more_headers +Authorization: bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJrZXkiOiJ1c2VyLWtleSIsIm5iZiI6MTcyNzI3NDk4M30.N6ebc4U5ms976pwKZ_iQ88w_uJKqUVNtTYZ_nXhRpWo +--- error_code: 200 +--- response_body +JWT found in ctx. Payload key: user-key