Json Web Token(RFC7519), 是一种便捷的可用于网关进行请求认证的j鉴权方案,API 网关
可以通过托管用户的Public JWK
实现对请求进行JWT认证,并将claims
作为后端参数转发给后端,已方便用户简化开发后端应用的开发。
原有在API上配置的OpenId Connect
功能目前可以通过JWT认证插件
实现,推荐使用JWT认证
插件配置,相比配置在API上的OpenId Connect
配置,JWT认证
插件具备以下优势:
- 不再需要额外配置一个
授权API
,可以用任何方式来生成与分发JWT
,API网关仅负责通过公钥JWK
认证JWT
- 支持不含
kid
的jwk
- 支持配置多个
jwk
- 支持直接从
header
或query
读取Token,不需要每个API都设置Token参数 - 当
JWT
以Authorization bearer {token}
方式传输时,可以通过parameter: Authorization
,parameterLocation: header
方式配置已实现正确的Token读取 - 通过添加
preventJtiReplay: true
配置,可支持基于claim:jti
的防重放检查 - 通过添加
bypassEmptyToken: true
配置,可在Token不存在时跳过验证直接转发给后端 - 通过添加
ignoreExpirationCheck: true
配置,可忽略Token的exp
超期校验
如果你配置了JWT认证插件
并绑定到了已配置了OpenId Connect
功能的API上,原有API
上的OpenId Connect
的功能将被插件的配置覆盖。
1. 获取JWK (Json Web Key)
JWT认证插件通过Json Web Key(RFC7517),实现JWT的签名与认证,配置JWT认证插件
首先需要生成一个有效的Json Web Key
,您可以通过自行生成,或搜索Json Web Key Generator
寻找可用的在线生成工具,如mkjwk.org,一个可用的Json Web Key
大概如下所示,其中私钥用于对Token进行签名,公钥需要配置在JWT认证
插件中用于对Token进行签名,一个合法的JWK大概格式如下:
{
"kty": "RSA",
"e": "AQAB",
"kid": "O9fpdhrViq2zaaaBEWZITz",
"use": "sig",
"alg": "RS256",
"n": "qSVxcknOm0uCq5vGsOmaorPDzHUubBmZZ4UXj-9do7w9X1uKFXAnqfto4TepSNuYU2bA_-tzSLAGBsR-BqvT6w9SjxakeiyQpVmexxnDw5WZwpWenUAcYrfSPEoNU-0hAQwFYgqZwJQMN8ptxkd0170PFauwACOx4Hfr-9FPGy8NCoIO4MfLXzJ3mJ7xqgIZp3NIOGXz-GIAbCf13ii7kSStpYqN3L_zzpvXUAos1FJ9IPXRV84tIZpFVh2lmRh0h8ImK-vI42dwlD_hOIzayL1Xno2R0T-d5AwTSdnep7g-Fwu8-sj4cCRWq3bd61Zs2QOJ8iustH0vSRMYdP5oYQ"
}
这里展示的是json格式,当使用yaml格式配置插件,需要转换*
JWT认证插件
只需要配置Public Key
, 请妥善保存好您的Private Key
,目前JWT认证插件支持以下算法:
签名算法 | 支持的alg 取值
|
---|---|
RSASSA-PKCS1-V1_5 with SHA-2 | RS256, RS384, RS512 |
Elliptic Curve (ECDSA) with SHA-2 | ES256, ES384, ES512 |
HMAC using SHA-2 | HS256, HS384, HS512 |
2. 插件配置
您可以选择json或者yaml格式的来配置您的插件,两种格式的schema相同,请搜索yaml to json
转换工具来进行配置格式的转换,yaml格式的模板见下表。
---
parameter: X-Token # 从指定的参数中获取JWT, 对应API的参数
parameterLocation: header # API为映射模式时可选, API为透传模式下必填, 用于指定JWT的读取位置, 仅支持`query`,`header`
preventJtiReplay: false # 是否开启针对`jti`的防重放检查, 默认: false
bypassEmptyToken: false # 当`jwt`为空时是否允许验证通过
ignoreExpirationCheck: false # 是否允许忽略`exp`超期时间的检查
claimParameters: # claims参数转换, 网关会将jwt claims映射为后端参数
- claimName: aud # claim名称,支持公共和私有
parameterName: X-Aud # 映射后参数名称
location: header # 映射后参数位置, 支持`query,header,path,formData`
- claimName: userId # claim名称,支持公共和私有
parameterName: userId # 映射后参数名称
location: query # 映射后的参数位置, 支持`query,header,path,formData`
#
# `Json Web Key`的`Public Key`
jwk:
kty: RSA
e: AQAB
use: sig
alg: RS256
n: qSVxcknOm0uCq5vGsOmaorPDzHUubBmZZ4UXj-9do7w9X1uKFXAnqfto4TepSNuYU2bA_-tzSLAGBsR-BqvT6w9SjxakeiyQpVmexxnDw5WZwpWenUAcYrfSPEoNU-0hAQwFYgqZwJQMN8ptxkd0170PFauwACOx4Hfr-9FPGy8NCoIO4MfLXzJ3mJ7xqgIZp3NIOGXz-GIAbCf13ii7kSStpYqN3L_zzpvXUAos1FJ9IPXRV84tIZpFVh2lmRh0h8ImK-vI42dwlD_hOIzayL1Xno2R0T-d5AwTSdnep7g-Fwu8-sj4cCRWq3bd61Zs2QOJ8iustH0vSRMYdP5oYQ
#
# 可以支持配置多个JWK, 可以与jwk字段一起配置
# 配置多个JWK时,kid是必选的,如果JWT中没有提供kid,则校验失败
jwks:
- kid: O9fpdhrViq2zaaaBEWZITz # 在只配置一个JWK时,kid是可选的,但如果中JWT包含了kid,网关会校验kid的一致性
kty: RSA
e: AQAB
use: sig
alg: RS256
n: qSVxcknOm0uCq5v....
- kid: 10fpdhrViq2zaaaBEWZITz # 在只配置一个JWK时,kid是可选的,但如果中JWT包含了kid,网关会校验kid的一致性
kty: RSA
e: AQAB
use: sig
alg: RS256
n: qSVxcknOm0uCq5v...
JWT认证插件
会使用配置的parameter
与parameterLocation
来读取JWT的值,如:parameter: X-Token
,parameterLocation: header
表示从请求的X-Token
头读取JWT- 如果API上配置了与
paramter
配置同名的参数时,paramterLocation
可以忽略,否则会在调用时报错 - 如果使用Authorization头传输Token,如:
Authorization bearer {token}
, 可以通过parameter: Authorization
,parameterLocation: header
方式配置,JWT插件可以正确读取到Token的取值 - 当配置了
preventJtiReplay: true
时,插件会使用claims
中的jti
字段进行防重放检查 - 当配置了
bypassEmptyToken: true
时,当Token参数为空时,允许跳过检查,直接转发请求给后端 - 当配置了
ignoreExpirationCheck: true
时,会跳过exp
的超期检查,否则网关会检查Token是否已超期 - 如果需要API网关将Token中的
claims
转发给后端应用,可以通过tokenParameters
字段配置转发参数claimName
: token中claim的名字,当配置HS256,HS384,HS512类型的Key时,秘钥为Base64 UrlEncode后的值,如遇到Invalid Signature问题,请检查您的Key的格式是否与生成Token的Key一致支持配置kid
parameterName
: 转发到后端的参数名称location
: 转发到后端的参数位置,支持header
,query
,path
,formData
- 当配置为
path
时,后端path必须包含同名的参数,如/path/{userId}
- 当配置为
formData
时,仅支持在参数映射
且包体为form
格式下才能正确映射到后端的form中
- 当配置为
- 可以在
jwk
字段中配置单个Key,或在jwks
字中配置多个Key- 不包含
kid
字段的Key只允许配置一个 - 包含
kid
的Key可以配置多个,但kid
必须唯一
- 不包含
3. 校验规则
- 插件会通过配置的
paramater
与parameterToken
来获取到Token, 如果希望在Token不存在时仍然转发请求给后端,需要配置bypassEmptyToken: true
- 当配置多个Key是的选择原则为
- 优先选择与请求Token中
kid
一致的Key来进行签名校验 - 不含
kid
的Key只能配置一个,当不存在kid
与请求Token一致的情况时,使用不含kid
的Key执行签名校验 - 如果没有配置不含
kid
的Key,如果请求Token中未包含kid
,或通过kid
未匹配到Key则报错A403JK
- 优先选择与请求Token中
- 如果Token中包含了
iat
,nbf
,exp
字段,JWT插件会校验时间字段的合法性 - 默认情况下,API网关会校验Token的
exp
过期时间字段,如果希望跳过exp
的超期检查,需要配置ignoreExpirationCheck: true
- 如果配置了
tokenParameters
字段转发,当Token的claims
中包含对应的字段时,claim
字段会转发给后端,不存在的claim
不会转发
4. 配置案例
4.1. 配置单个JWK
---
parameter: X-Token # 从指定的参数中获取JWT, 对应API的参数
parameterLocation: header # API为映射模式时可选, API为透传模式下必填, 用于指定JWT的读取位置, 仅支持`query`,`header`
claimParameters: # claims参数转换, 网关会将jwt claims映射为后端参数
- claimName: aud # claim名称,支持公共和私有
parameterName: X-Aud # 映射后参数名称
location: header # 映射后参数位置, 支持`query,header,path,formData`
- claimName: userId # claim名称,支持公共和私有
parameterName: userId # 映射后参数名称
location: query # 映射后的参数位置, 支持`query,header,path,formData`
preventJtiReplay: false # 是否开启针对`jti`的防重放检查, 默认: false
#
# `Json Web Key`的`Public Key`
jwk:
kty: RSA
e: AQAB
use: sig
alg: RS256
n: qSVxcknOm0uCq5vGsOmaorPDzHUubBmZZ4UXj-9do7w9X1uKFXAnqfto4TepSNuYU2bA_-tzSLAGBsR-BqvT6w9SjxakeiyQpVmexxnDw5WZwpWenUAcYrfSPEoNU-0hAQwFYgqZwJQMN8ptxkd0170PFauwACOx4Hfr-9FPGy8NCoIO4MfLXzJ3mJ7xqgIZp3NIOGXz-GIAbCf13ii7kSStpYqN3L_zzpvXUAos1FJ9IPXRV84tIZpFVh2lmRh0h8ImK-vI42dwlD_hOIzayL1Xno2R0T-d5AwTSdnep7g-Fwu8-sj4cCRWq3bd61Zs2QOJ8iustH0vSRMYdP5oYQ
4.2. 配置多个JWK
---
parameter: Authorization # 从Authorization头中获取Token
parameterLocation: header # 从Authorization头中获取Token
claimParameters: # claims参数转换, 网关会将jwt claims映射为后端参数
- claimName: aud # claim名称,支持公共和私有
parameterName: X-Aud # 映射后参数名称
location: header # 映射后参数位置, 支持`query,header,path,formData`
- claimName: userId # claim名称,支持公共和私有
parameterName: userId # 映射后参数名称
location: query # 映射后的参数位置, 支持`query,header,path,formData`
preventJtiReplay: true # 是否开启针对`jti`的防重放检查, 默认: false
jwks:
- kid: O9fpdhrViq2zaaaBEWZITz # 配置多个JWK时,需要使用不同的`kid`
kty: RSA
e: AQAB
use: sig
alg: RS256
n: qSVxcknOm0uCq5v....
- kid: 10fpdhrViq2zaaaBEWZITz # 配置多个JWK时,需要使用不同的`kid`
kty: RSA
e: AQAB
use: sig
alg: RS256
n: qSVxcknOm0uCq5v...
5. 相关错误码
Status | Code | Message | Description |
---|---|---|---|
400 | I400JR | JWT required | 未找到JWT参数 |
403 | S403JI | Claim jti is required when preventJtiReplay:true |
当在JWT授权插件 中配置了防重放功能时,请求未提供有效的jti |
403 | S403JU | Claim jti in JWT is used
|
当在JWT授权插件 中配置了防重放功能时,请求提供的jti 已被使用
|
403 | A403JT | Invalid JWT: ${Reason} | 请求中提供的JWT 非法
|
400 | I400JD | JWT Deserialize Failed: ${Token} |
请求中提供的JWT 解析失
|
403 | A403JK | No matching JWK, kid:${kid} not found
|
请求JWT 中的kid 没有匹配的JWK |
403 | A403JE | JWT is expired at ${Date} |
请求中提供的JWT 已过期
|
400 | I400JP | Invalid JWT plugin config: ${JWT} | JWT授权 插件配置错误
|
当出现非预期应答码是,请检查HTTP应答中的X-Ca-Error-Code
头中获取ErrorCode
,从X-Ca-Error-Message
头中获取ErrorMessage
当出现A403JT
或I400JD
错误码时,可访问jwt.io网站来检查自己的Token合法性与格式。
6. 使用限制
- 插件元数据的大小限制为16380个字符。
- 转发参数列表最大限制为16个,
claimName
与parameterName
长度不超过32个字符, 仅支持[A-Za-z0-9-_]。 - JWK的
alg
支持列表为:RS256, RS384, RS512, ES256, ES384, ES512, HS256, HS384, HS512。
在文档使用中是否遇到以下问题
更多建议
匿名提交