jwt-auth插件实现了基于JWT(JSON Web Tokens)进行认证鉴权的功能,支持从HTTP请求的URL参数、请求头、Cookie字段解析JWT,同时验证该Token是否有权限访问。相较于配置JWT认证鉴权,jwt-auth插件额外提供了调用方身份识别的能力,支持对不同调用方配置不同的JWT凭证。本文介绍如何配置jwt-auth插件。
插件类型
认证鉴权。
配置字段
名称 | 数据类型 | 填写要求 | 默认值 | 描述 |
consumers | array of object | 必填。 | - | 配置服务的调用者,用于对请求进行认证。 |
_rules_ | array of object | 选填。 | - | 配置特定路由或域名的访问权限列表,用于对请求进行鉴权。 |
子项consumers
中每一项的配置字段说明如下。
名称 | 数据类型 | 填写要求 | 默认值 | 描述 |
name | string | 必填。 | - | 配置该consumer的名称。 |
jwks | string | 选填。jwks和remote_jwks必填一个。 | - | JSON Web Key (JWK)指定的JSON格式字符串,是由验证JWT中签名的公钥(或对称密钥)组成的JSON Web Key Set。 |
remote_jwks | object | 选填。jwks和remote_jwks必填一个。 | {"uri":"http://127.0.0.1/keys","service":"test.static","port":"80","ttl":30000,"timeout":3000} | 用于从指定服务的指定uri定时拉取jwks,和jwks字段同时配置时,以此字段配置拉取的jwks优先。 |
issuer | string | 必填。 | - | JWT的签发者,需要和payload中的iss字段保持一致。 |
claims_to_headers | array of object | 选填。 | - | 抽取JWT的payload中指定字段,设置到指定的请求头中,然后转发给后端。 |
from_headers | array of object | 选填。 | [{"name":"Authorization","value_prefix":"Bearer"}] | 从指定的请求头中抽取JWT。 |
from_params | array of string | 选填。 | access_token | 从指定的URL参数中抽取JWT。 |
from_cookies | array of string | 选填。 | - | 从指定的cookie中抽取JWT。 |
clock_skew_seconds | number | 选填。 | 60 | 校验JWT的exp和iat字段时允许的时钟偏移量,单位为秒。 |
keep_token | bool | 选填。 | true | 转发给后端时是否保留JWT。 |
只有当from_headers
,from_params
,from_cookies
均未配置时,才会使用默认值。
from_headers
中每一项的配置字段说明如下。名称
数据类型
填写要求
默认值
描述
name
string
必填。
-
抽取JWT的请求Header。
value_prefix
string
必填。
-
对请求Header的value去除此前缀,剩余部分作为JWT。
claims_to_headers
中每一项的配置字段说明如下。名称
数据类型
填写要求
默认值
描述
claim
string
必填。
-
JWT payload中的指定字段,要求必须是字符串或无符号整数类型。
header
string
必填。
-
从payload取出字段的值设置到这个请求头中,转发给后端。
override
bool
选填。
true
true时,存在同名请求头会进行覆盖。
false时,追加同名请求头。
remote_jwks
中每一项的配置字段说明如下。名称
数据类型
填写要求
默认值
描述
uri
string
必填。
-
请求URL。
service
string
必填。
-
K8s服务填写示例:foo.default.svc.cluster.local。
Nacos服务填写示例:foo.DEFAULT-GROUP.public.nacos。
如果是名为test的DNS服务,则填写test.dns。
如果是名为test的静态IP服务,则填写test.static。
port
bool
必填。
-
服务端口
timeout
bool
选填。
3000
服务请求超时时间,单位是毫秒
ttl
bool
选填。
30000
缓存时间,单位是毫秒
子项_rules_
中每一项的配置字段说明如下。
名称 | 数据类型 | 填写要求 | 默认值 | 描述 |
_match_route_ | array of string | 选填。 | - | 配置要匹配的路由名称。 |
_match_domain_ | array of string | 选填。 | - | 配置要匹配的域名。 |
_disable_ | bool | 选填 | false | 匹配到当前规则时,插件功能不启用。 |
allow | array of string | 必填。 | - | 对于符合匹配条件的请求,配置允许访问的consumer名称。 |
若不配置
_rules_
字段,则默认对当前网关实例的所有路由开启认证。对于通过认证鉴权的请求,请求的Header会被添加一个
X-Mse-Consumer
字段,用以标识调用者的名称。
配置示例
对特定路由或域名开启
以下配置将对网关特定路由或域名开启Jwt Auth认证和鉴权。
如果一个JWT能匹配多个jwks,则按照配置顺序命中第一个匹配的consumer。
consumers:
- name: consumer1
issuer: abcd
jwks: |
{
"keys": [
{
"kty": "oct",
"kid": "123",
"k": "hM0k3AbXBPpKOGg__Ql2Obcq7s60myWDpbHXzgKUQdYo7YCRp0gUqkCnbGSvZ2rGEl4YFkKqIqW7mTHdj-bcqXpNr-NOznEyMpVPOIlqG_NWVC3dydBgcsIZIdD-MR2AQceEaxriPA_VmiUCwfwL2Bhs6_i7eolXoY11EapLQtutz0BV6ZxQQ4dYUmct--7PLNb4BWJyQeWu0QfbIthnvhYllyl2dgeLTEJT58wzFz5HeNMNz8ohY5K0XaKAe5cepryqoXLhA-V-O1OjSG8lCNdKS09OY6O0fkyweKEtuDfien5tHHSsHXoAxYEHPFcSRL4bFPLZ0orTt1_4zpyfew",
"alg": "HS256"
}
]
}
- name: consumer2
issuer: abc
jwks: |
{
"keys": [
{
"kty": "RSA",
"e": "AQAB",
"use": "sig",
"kid": "123",
"alg": "RS256",
"n": "i0B67f1jggT9QJlZ_8QL9QQ56LfurrqDhpuu8BxtVcfxrYmaXaCtqTn7OfCuca7cGHdrJIjq99rz890NmYFZuvhaZ-LMt2iyiSb9LZJAeJmHf7ecguXS_-4x3hvbsrgUDi9tlg7xxbqGYcrco3anmalAFxsbswtu2PAXLtTnUo6aYwZsWA6ksq4FL3-anPNL5oZUgIp3HGyhhLTLdlQcC83jzxbguOim-0OEz-N4fniTYRivK7MlibHKrJfO3xa_6whBS07HW4Ydc37ZN3Rx9Ov3ZyV0idFblU519nUdqp_inXj1eEpynlxH60Ys_aTU2POGZh_25KXGdF_ZC_MSRw"
}
]
}
# 使用 _rules_ 字段进行细粒度规则配置
_rules_:
# 规则一:按路由名称匹配生效
- _match_route_:
- route-a
- route-b
allow:
- consumer1
# 规则二:按域名匹配生效
- _match_domain_:
- "*.example.com"
- test.com
allow:
- consumer2
_match_route_
中指定的route-a
和route-b
即在创建网关路由时填写的路由名称,当匹配到这两个路由时,将允许name
为consumer1
的调用者访问,其他调用者不允许访问。_match_domain_
中指定的*.example.com
和test.com
用于匹配请求的域名,当发现域名匹配时,将允许name
为consumer2
的调用者访问,其他调用者不允许访问。
根据该配置,下列请求可以允许访问。假设以下请求会匹配到route-a这条路由。
将JWT设置在URL参数中。
curl 'http://xxx.hello.com/test?access_token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IjEyMyJ9.eyJpc3MiOiJhYmNkIiwic3ViIjoidGVzdCIsImlhdCI6MTY2NTY2MDUyNywiZXhwIjoxODY1NjczODE5fQ.-vBSV0bKeDwQcuS6eeSZN9dLTUnSnZVk8eVCXdooCQ4'
将JWT设置在HTTP请求头中。
curl http://xxx.hello.com/test -H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IjEyMyJ9.eyJpc3MiOiJhYmNkIiwic3ViIjoidGVzdCIsImlhdCI6MTY2NTY2MDUyNywiZXhwIjoxODY1NjczODE5fQ.-vBSV0bKeDwQcuS6eeSZN9dLTUnSnZVk8eVCXdooCQ4'
认证鉴权通过后,请求的Header中会被添加一个
X-Mse-Consumer
字段,在此例中其值为consumer1
,用以标识调用方的名称。下列请求将拒绝访问。
请求未提供JWT,返回401。
curl http://xxx.hello.com/test
根据请求提供的JWT匹配到的调用者无访问权限,返回403。
# consumer1不在*.example.com的allow列表里 curl 'http://xxx.example.com/test' -H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IjEyMyJ9.eyJpc3MiOiJhYmNkIiwic3ViIjoidGVzdCIsImlhdCI6MTY2NTY2MDUyNywiZXhwIjoxODY1NjczODE5fQ.-vBSV0bKeDwQcuS6eeSZN9dLTUnSnZVk8eVCXdooCQ4'
网关实例级别开启,但特定路由关闭
global_auth: true
consumers:
- name: consumer1
issuer: abcd
jwks: |
{
"keys": [
{
"kty": "oct",
"kid": "123",
"k": "hM0k3AbXBPpKOGg__Ql2Obcq7s60myWDpbHXzgKUQdYo7YCRp0gUqkCnbGSvZ2rGEl4YFkKqIqW7mTHdj-bcqXpNr-NOznEyMpVPOIlqG_NWVC3dydBgcsIZIdD-MR2AQceEaxriPA_VmiUCwfwL2Bhs6_i7eolXoY11EapLQtutz0BV6ZxQQ4dYUmct--7PLNb4BWJyQeWu0QfbIthnvhYllyl2dgeLTEJT58wzFz5HeNMNz8ohY5K0XaKAe5cepryqoXLhA-V-O1OjSG8lCNdKS09OY6O0fkyweKEtuDfien5tHHSsHXoAxYEHPFcSRL4bFPLZ0orTt1_4zpyfew",
"alg": "HS256"
}
]
}
- name: consumer2
issuer: abc
jwks: |
{
"keys": [
{
"kty": "RSA",
"e": "AQAB",
"use": "sig",
"kid": "123",
"alg": "RS256",
"n": "i0B67f1jggT9QJlZ_8QL9QQ56LfurrqDhpuu8BxtVcfxrYmaXaCtqTn7OfCuca7cGHdrJIjq99rz890NmYFZuvhaZ-LMt2iyiSb9LZJAeJmHf7ecguXS_-4x3hvbsrgUDi9tlg7xxbqGYcrco3anmalAFxsbswtu2PAXLtTnUo6aYwZsWA6ksq4FL3-anPNL5oZUgIp3HGyhhLTLdlQcC83jzxbguOim-0OEz-N4fniTYRivK7MlibHKrJfO3xa_6whBS07HW4Ydc37ZN3Rx9Ov3ZyV0idFblU519nUdqp_inXj1eEpynlxH60Ys_aTU2POGZh_25KXGdF_ZC_MSRw"
}
]
}
# 使用 _rules_ 字段进行细粒度规则配置
_rules_:
# 按路由名称匹配,关闭插件功能
- _match_route_:
- route-b
_disable_: true
此例_match_route_
中指定的route-b
即在创建网关路由时填写的路由名称。因为_disable_
设置为true
,当匹配到这个路由时,将关闭此插件功能,不进行JWT认证,所有人均可访问。
当没有匹配到route-b
路由时,因为全局配置中global_auth
设置为了true
,表明对所有请求开启认证,所以将进行JWT认证,并且允许consumer1
和consumer2
都能访问。
域名级别开启,但特定路由关闭
consumers:
- name: consumer1
issuer: abcd
jwks: |
{
"keys": [
{
"kty": "oct",
"kid": "123",
"k": "hM0k3AbXBPpKOGg__Ql2Obcq7s60myWDpbHXzgKUQdYo7YCRp0gUqkCnbGSvZ2rGEl4YFkKqIqW7mTHdj-bcqXpNr-NOznEyMpVPOIlqG_NWVC3dydBgcsIZIdD-MR2AQceEaxriPA_VmiUCwfwL2Bhs6_i7eolXoY11EapLQtutz0BV6ZxQQ4dYUmct--7PLNb4BWJyQeWu0QfbIthnvhYllyl2dgeLTEJT58wzFz5HeNMNz8ohY5K0XaKAe5cepryqoXLhA-V-O1OjSG8lCNdKS09OY6O0fkyweKEtuDfien5tHHSsHXoAxYEHPFcSRL4bFPLZ0orTt1_4zpyfew",
"alg": "HS256"
}
]
}
- name: consumer2
issuer: abc
jwks: |
{
"keys": [
{
"kty": "RSA",
"e": "AQAB",
"use": "sig",
"kid": "123",
"alg": "RS256",
"n": "i0B67f1jggT9QJlZ_8QL9QQ56LfurrqDhpuu8BxtVcfxrYmaXaCtqTn7OfCuca7cGHdrJIjq99rz890NmYFZuvhaZ-LMt2iyiSb9LZJAeJmHf7ecguXS_-4x3hvbsrgUDi9tlg7xxbqGYcrco3anmalAFxsbswtu2PAXLtTnUo6aYwZsWA6ksq4FL3-anPNL5oZUgIp3HGyhhLTLdlQcC83jzxbguOim-0OEz-N4fniTYRivK7MlibHKrJfO3xa_6whBS07HW4Ydc37ZN3Rx9Ov3ZyV0idFblU519nUdqp_inXj1eEpynlxH60Ys_aTU2POGZh_25KXGdF_ZC_MSRw"
}
]
}
# 使用 _rules_ 字段进行细粒度规则配置
_rules_:
# 规则一:按路由名称匹配,关闭插件功能
- _match_route_:
- route-b
_disable_: true
# 规则二:按域名匹配生效
- _match_domain_:
- "*.example.com"
allow:
- consumer1
- consumer2
此例_match_route_
中指定的route-b
即在创建网关路由时填写的路由名称。因为_disable_
设置为true
,当匹配到这个路由时,将关闭此插件功能,不进行JWT认证,所有人均可访问。
此例_match_domain_
中指定的*.example.com
用于匹配请求的域名。当发现域名匹配时,将允许name
为consumer2
或consumer1
的调用者访问,其他调用者不允许访问。
配置规则顺序会依次执行匹配,有任一规则匹配到,就会执行对应配置,不再匹配其他规则。因为这里配置路由匹配优先级高于域名,即可实现对于域名整体生效,而对域名下的特定路由关闭。
相关错误码
HTTP状态码 | 出错信息 | 原因说明 |
401 | Jwt missing | 请求头未提供JWT。 |
401 | Jwt expired | JWT已经过期。 |
401 | Jwt verification fails | JWT payload校验失败,如iss不匹配。 |
403 | Access Denied | 无权限访问当前路由。 |
- 本页导读 (1)