在Kong网关快速入门指南 一文中介绍了Key认证和HMAC认证方式,本文介绍在Kong网关中使用JWT认证。
参见:
简单归纳一下JWT(JSON Web Token)的特点:
在Service下添加JWT插件,全部保持默认值。
查看插件详情:
uri param names: `jwt`
key claim name: `iss`
secret is base64: NO #NO表示不对secret作Base64编码
headers names: `authorization`
说明:
key
作为JWT payload中的iss
字段(issuer缩写,令牌颁发者)。保持全部默认值来生成Consumer的JWT credentials。
示例:
{
"tags": null,
"secret": "pdDcyjZUrOaUY2HDIrrgRnG7ix0hNf7B",
"consumer": {
"id": "c3202163-d7b8-4604-8137-466109590fd2"
},
"algorithm": "HS256",
"rsa_public_key": null,
"id": "e23be144-26b9-4f3a-8938-ceddc34d2e23",
"created_at": 1626763334,
"key": "5D4Z0wB7A8RXVsfivcEZ2VlRGGlF09Lf"
}
说明:
key
为JWT payload里面的iss
(issuer的缩写,表示令牌颁发者)secret
为签名时用的密钥。"algorithm": "HS256"
表示用HmacSHA256算法。在Postman上新建Environment Variable:
jwt_secret:pdDcyjZUrOaUY2HDIrrgRnG7ix0hNf7B
- 对应JWT credential的secret
jwt_iss:5D4Z0wB7A8RXVsfivcEZ2VlRGGlF09Lf
- 对应JWT credential的key
在Request的Authorization中选择Type为“Bearer Token”,Token值为{{jwt_signed}}
。
Request的Pre-request Script如下:
// JWT generation script adapted from
// https://gist.github.com/corbanb/db03150abbe899285d6a86cc480f674d
var jwtSecret = pm.environment.get('jwt_secret') || ''
// Set headers for JWT
var header = {
'typ': 'JWT',
'alg': 'HS256'
};
// Prepare timestamp in seconds
var currentTimestamp = Math.floor(Date.now() / 1000)
var data = {
'iss': pm.environment.get('jwt_iss') || '',
'ist': pm.environment.get('jwt_ist') || '',
'iat': currentTimestamp,
'exp': currentTimestamp + 30, // expiry time is 30 seconds from time of creation
'jti': 'jwt_nonce'
}
function base64url(source) {
// Encode in classical base64
encodedSource = CryptoJS.enc.Base64.stringify(source)
// Remove padding equal characters
encodedSource = encodedSource.replace(/=+$/, '')
// Replace characters according to base64url specifications
encodedSource = encodedSource.replace(/\+/g, '-')
encodedSource = encodedSource.replace(/\//g, '_')
return encodedSource
}
// encode header
var stringifiedHeader = CryptoJS.enc.Utf8.parse(JSON.stringify(header))
var encodedHeader = base64url(stringifiedHeader)
// encode data
var stringifiedData = CryptoJS.enc.Utf8.parse(JSON.stringify(data))
var encodedData = base64url(stringifiedData)
// build token
var token = `${encodedHeader}.${encodedData}`
// sign token
var signature = CryptoJS.HmacSHA256(token, jwtSecret)
signature = base64url(signature)
var signedToken = `${token}.${signature}`
pm.environment.set('jwt_signed', signedToken)
console.log('Signed and encoded JWT', signedToken)
说明:
'exp': currentTimestamp + 30,
- 30s有效时间,可以根据实际情况调整,一般不超过几分钟。参见:
生成的JWT token示例如下:
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiI1RDRaMHdCN0E4UlhWc2ZpdmNFWjJWbFJHR2xGMDlMZiIsImlzdCI6IiIsImlhdCI6MTYyNjc2OTM1MSwiZXhwIjoxNjI2NzY5MzgxLCJqdGkiOiJqd3Rfbm9uY2UifQ.rFisEEzpWfMVhO82G_ktUr_ojcer-MkC30jyBbjBll4
可复制该值到https://jwt.io/ 中查看解码结果。
示例:
Header:
{
"typ": "JWT",
"alg": "HS256"
}
Payload:
{
"iss": "5D4Z0wB7A8RXVsfivcEZ2VlRGGlF09Lf",
"ist": "",
"iat": 1626769351,
"exp": 1626769381,
"jti": "jwt_nonce"
}
上面的过程只适合于一个Service只有有限几个Consumer的情况。
还可以结合OpenID Connect + JWT将每个用户都当作一个Consumer来作更细粒度的JWT认证。
参见:
可惜的是Kong OpenID Connect Plugin只有在Kong收费版上才有,虽然网络上有一个开源的kong-oidc 插件项目,但是已经有几年没有维护了。