You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@apisix.apache.org by ju...@apache.org on 2025/03/05 07:02:34 UTC

(apisix) branch master updated: feat(jwt-auth): store JWT in the request context (#11675)

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 <ri...@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