Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(jwt-auth): store JWT in the request context #11675

Open
wants to merge 10 commits into
base: master
Choose a base branch
from
8 changes: 8 additions & 0 deletions apisix/plugins/jwt-auth.lua
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,10 @@ local schema = {
default = "key",
minLength = 1,
},
store_in_ctx = {
type = "boolean",
default = false
},
anonymous_consumer = schema_def.anonymous_consumer_schema,
},
}
Expand Down Expand Up @@ -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_obj = jwt_obj
end

return consumer, consumer_conf
end

Expand Down
15 changes: 8 additions & 7 deletions docs/en/latest/plugins/jwt-auth.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 in the request context. 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.

Expand Down
1 change: 1 addition & 0 deletions docs/zh/latest/plugins/jwt-auth.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 存储在请求上下文中。这允许在同一请求上随后运行的低优先级插件检索和使用 JWT 令牌。 |

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

Expand Down
120 changes: 120 additions & 0 deletions t/plugin/jwt-auth4.t
Original file line number Diff line number Diff line change
Expand Up @@ -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: enable jwt auth plugin without store_in_ctx
--- 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_obj then
ngx.status = 200
ngx.say(\"JWT found in ctx. Payload key: \" .. ctx.jwt_obj.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: enable jwt auth plugin with store_in_ctx
--- 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_obj then
ngx.status = 200
ngx.say(\"JWT found in ctx. Payload key: \" .. ctx.jwt_obj.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 8: verify (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 9: verify (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
Loading