Skip to content

Commit 381595e

Browse files
authored
feat(jwt-auth): store JWT in the request context (#11675)
1 parent 1460edd commit 381595e

File tree

4 files changed

+137
-7
lines changed

4 files changed

+137
-7
lines changed

apisix/plugins/jwt-auth.lua

+8
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,10 @@ local schema = {
5656
default = "key",
5757
minLength = 1,
5858
},
59+
store_in_ctx = {
60+
type = "boolean",
61+
default = false
62+
},
5963
anonymous_consumer = schema_def.anonymous_consumer_schema,
6064
},
6165
}
@@ -295,6 +299,10 @@ local function find_consumer(conf, ctx)
295299
return nil, nil, "failed to verify jwt"
296300
end
297301

302+
if conf.store_in_ctx then
303+
ctx.jwt_auth_payload = jwt_obj.payload
304+
end
305+
298306
return consumer, consumer_conf
299307
end
300308

docs/en/latest/plugins/jwt-auth.md

+8-7
Original file line numberDiff line numberDiff line change
@@ -52,13 +52,14 @@ NOTE: `encrypt_fields = {"secret"}` is also defined in the schema, which means t
5252

5353
For Route:
5454

55-
| Name | Type | Required | Default | Description |
56-
|------------------|---------|----------|---------------|-------------------------------------------------------------------------------------------------|
57-
| header | string | False | authorization | The header to get the token from. |
58-
| query | string | False | jwt | The query string to get the token from. Lower priority than header. |
59-
| cookie | string | False | jwt | The cookie to get the token from. Lower priority than query. |
60-
| hide_credentials | boolean | False | false | Set to true will not pass the authorization request of header\query\cookie to the Upstream. |
61-
| key_claim_name | string | False | key | The name of the JWT claim that contains the user key (corresponds to Consumer's key attribute). |
55+
| Name | Type | Required | Default | Description |
56+
|------------------|---------|----------|---------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------|
57+
| header | string | False | authorization | The header to get the token from. |
58+
| query | string | False | jwt | The query string to get the token from. Lower priority than header. |
59+
| cookie | string | False | jwt | The cookie to get the token from. Lower priority than query. |
60+
| hide_credentials | boolean | False | false | Set to true will not pass the authorization request of header\query\cookie to the Upstream. |
61+
| key_claim_name | string | False | key | The name of the JWT claim that contains the user key (corresponds to Consumer's key attribute). |
62+
| 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. |
6263

6364
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.
6465

docs/zh/latest/plugins/jwt-auth.md

+1
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ Route 端:
5959
| cookie | string || jwt | 设置我们从哪个 cookie 获取 token,优先级低于 query。 |
6060
| hide_credentials | boolean || false | 该参数设置为 `true` 时,则不会将含有认证信息的 header\query\cookie 传递给 Upstream。|
6161
| key_claim_name | string || key | 包含用户密钥(对应消费者的密钥属性)的 JWT 声明的名称。|
62+
| store_in_ctx | boolean || false | 设置为 `true` 将会将 JWT 负载存储在请求上下文 (`ctx.jwt_auth_payload`) 中。这允许在同一请求上随后运行的低优先级插件检索和使用 JWT 令牌。 |
6263

6364
您可以使用 [HashiCorp Vault](https://www.vaultproject.io/) 实施 `jwt-auth`,以从其[加密的 KV 引擎](https://developer.hashicorp.com/vault/docs/secrets/kv) 使用 [APISIX Secret](../terminology/secret.md) 资源。
6465

t/plugin/jwt-auth4.t

+120
Original file line numberDiff line numberDiff line change
@@ -230,3 +230,123 @@ qr/\\"secret\\" validation failed: string too short, expected at least 1, got 0/
230230
--- error_code: 400
231231
--- response_body eval
232232
qr/\\"key\\" validation failed: string too short, expected at least 1, got 0/
233+
234+
235+
236+
=== TEST 6: store_in_ctx disabled
237+
--- config
238+
location /t {
239+
content_by_lua_block {
240+
local t = require("lib.test_admin").test
241+
local code, body = t('/apisix/admin/routes/1',
242+
ngx.HTTP_PUT,
243+
[[{
244+
"plugins": {
245+
"jwt-auth": {},
246+
"serverless-post-function": {
247+
"phase": "rewrite",
248+
"functions": [
249+
"return function(conf, ctx)
250+
if ctx.jwt_auth_payload then
251+
ngx.status = 200
252+
ngx.say(\"JWT found in ctx. Payload key: \" .. ctx.jwt_auth_payload.key)
253+
return ngx.exit(200)
254+
else
255+
ngx.status = 401
256+
ngx.say(\"JWT not found in ctx.\")
257+
return ngx.exit(401)
258+
end
259+
end"
260+
]
261+
}
262+
},
263+
"upstream": {
264+
"nodes": {
265+
"127.0.0.1:1980": 1
266+
},
267+
"type": "roundrobin"
268+
},
269+
"uri": "/jwt-auth-no-ctx"
270+
}]]
271+
)
272+
273+
if code >= 300 then
274+
ngx.status = code
275+
end
276+
ngx.say(body)
277+
}
278+
}
279+
--- response_body
280+
passed
281+
282+
283+
284+
=== TEST 7: verify store_in_ctx disabled (header with bearer)
285+
--- request
286+
GET /jwt-auth-no-ctx
287+
--- more_headers
288+
Authorization: bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJrZXkiOiJ1c2VyLWtleSIsIm5iZiI6MTcyNzI3NDk4M30.N6ebc4U5ms976pwKZ_iQ88w_uJKqUVNtTYZ_nXhRpWo
289+
--- error_code: 401
290+
--- response_body
291+
JWT not found in ctx.
292+
293+
294+
295+
=== TEST 8: store_in_ctx enabled
296+
--- config
297+
location /t {
298+
content_by_lua_block {
299+
local t = require("lib.test_admin").test
300+
local code, body = t('/apisix/admin/routes/2',
301+
ngx.HTTP_PUT,
302+
[[{
303+
"plugins": {
304+
"jwt-auth": {
305+
"store_in_ctx": true
306+
},
307+
"serverless-post-function": {
308+
"phase": "rewrite",
309+
"functions": [
310+
"return function(conf, ctx)
311+
if ctx.jwt_auth_payload then
312+
ngx.status = 200
313+
ngx.say(\"JWT found in ctx. Payload key: \" .. ctx.jwt_auth_payload.key)
314+
return ngx.exit(200)
315+
else
316+
ngx.status = 401
317+
ngx.say(\"JWT not found in ctx.\")
318+
return ngx.exit(401)
319+
end
320+
end"
321+
]
322+
}
323+
},
324+
"upstream": {
325+
"nodes": {
326+
"127.0.0.1:1980": 1
327+
},
328+
"type": "roundrobin"
329+
},
330+
"uri": "/jwt-auth-ctx"
331+
}]]
332+
)
333+
334+
if code >= 300 then
335+
ngx.status = code
336+
end
337+
ngx.say(body)
338+
}
339+
}
340+
--- response_body
341+
passed
342+
343+
344+
345+
=== TEST 9: verify store_in_ctx enabled (header with bearer)
346+
--- request
347+
GET /jwt-auth-ctx
348+
--- more_headers
349+
Authorization: bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJrZXkiOiJ1c2VyLWtleSIsIm5iZiI6MTcyNzI3NDk4M30.N6ebc4U5ms976pwKZ_iQ88w_uJKqUVNtTYZ_nXhRpWo
350+
--- error_code: 200
351+
--- response_body
352+
JWT found in ctx. Payload key: user-key

0 commit comments

Comments
 (0)