JWT是一种基于令牌的便捷请求认证鉴权方案。用户状态信息存储在token中,由客户端提供,函数(服务端)无需存储,是一种Serverless友好的鉴权方式。函数计算可以通过用户绑定在自定义域名上的Public JWKS实现对到达自定义域名上的请求进行JWT认证。并根据自定义域名上的配置,将claims作为参数转发给函数,函数无需对请求进行鉴权,只需关注业务逻辑即可。
背景信息
简介
JWT(JSON Web Token,RFC7519)是一种基于令牌的便捷请求认证鉴权方案。用户状态信息存储在token中,由客户端提供,函数(服务端)无需存储,是一种Serverless友好的鉴权方式。函数计算可以通过用户绑定在自定义域名上的Public JWKS实现对到达自定义域名上的请求进行JWT认证。并根据自定义域名上的配置,将claims作为参数转发给函数,函数无需对请求进行鉴权,只需关注业务逻辑即可。如果需要了解JWT的token认证流程及基础知识,请参见基于JWT的token认证和JWT简介。
JWT认证流程
自定义域名的JWT认证流程同HTTP触发器的JWT认证流程。
上图是函数计算HTTP触发器利用JWT实现认证的整个业务流程时序图(使用非对称加密算法),步骤详细解析如下。
客户端向自定义授权服务发起认证请求,请求中一般会携带终端用户的用户名和密码。
自定义授权服务读取请求中的验证信息(例如用户名、密码等)进行验证,验证通过之后使用私钥生成标准的
token。自定义授权服务将携带
token的应答返回给客户端,客户端需要将这个token缓存到本地。客户端向HTTP触发器发送业务请求,请求中携带
token。HTTP触发器使用用户设置的公钥对请求中的
token进行验证。验证通过之后,将请求透传给受保护的函数。
受保护的函数处理业务请求,并进行应答。
HTTP触发器将业务应答返回给客户端。
使用限制
可以使用任何方式来生成和分发JWT,函数计算通过触发器配置的Public JWKS来认证JWT。
支持不含
kid的JWK。支持为一个触发器配置多个JWK。
支持从
header、Query参数(GET)、表单参数(POST)和cookie中读取Token。支持将
claims作为header、Query参数(GET)、表单参数(POST)和cookie转发给函数。函数计算支持为一个自定义域名配置一组JWT(JWKS),在JWKS中寻找与token中的kid相同的JWK公钥,并使用这个公钥对token进行签名校验。一个自定义域名的JWKS最多只允许一个JWK的kid不存在或者为空字符串。
目前函数计算的JWT支持如下算法。
签名算法
alg取值
RSASSA-PKCS1-V1_5
RS256,RS384,RS512
RSASSA-PSS
PS256,PS384,PS512
Elliptic Curve (ECDSA)
ES256,ES384,ES512
HMAC
HS256,HS384,HS512
EdDSA
EdDSA
HMAC签名算法为对称加密,安全性相对较低,建议使用安全性更高的非对称加密算法。
使用非对称加密算法时,出于安全考虑,您的JWT中只需要包含公钥信息即可,不建议包含私钥信息。
建议使用HTTPS来对请求中的
token等敏感信息进行保护,可以有效避免Token泄露。
配置JWT认证
前提条件
已为函数配置自定义域名
操作步骤
登录函数计算控制台,在左侧导航栏,选择。
在顶部菜单栏,选择地域,然后在域名管理页面,单击目标域名。
单击右上角的编辑,在编辑自定义域名页面,设置以下配置项,然后单击保存。
认证方式选择为JWT 认证。

配置JWKS。
为自定义域名配置JWT鉴权,首先需要提供一个有效的JWKS(JSON Web Key Set)。您可以自行生成JWKS,或者搜索JSON Web Key Generator寻找在线可用的生成工具,例如mkjwk.org。如果您已经有pem格式的密钥,可以借助工具(例如jwx),将其转换为JWKS格式。JWKS示例如下。
本文以使用mkjwk.org工具生成JWKS为例进行介绍。如下图所示,选择Key Use、Algorithm和Show X.509,然后单击Generate。在您的代码中需要使用Private Key(下图中①)签发JWT Token,请妥善保存。您可以复制Public Key(下图中②)中的内容填入到控制台中的JWKS配置的keys数组中。


本文配置的JWKS示例如下。
{ "keys": [ { "alg": "RS256", "e": "AQAB", "kty": "RSA", "n": "u1LWgoomekdOMfB1lEe96OHehd4XRNCbZRm96RqwOYTTc28Sc_U5wKV2umDzolfoI682ct2BNnRRahYgZPhbOCzHYM6i8sRXjz9Ghx3QHw9zrYACtArwQxrTFiejbfzDPGdPrMQg7T8wjtLtkSyDmCzeXpbIdwmxuLyt_ahLfHelr94kEksMDa42V4Fi5bMW4cCLjlEKzBEHGmFdT8UbLPCvpgsM84JK63e5ifdeI9NdadbC8ZMiR--dFCujT7AgRRyMzxgdn2l-nZJ2ZaYzbLUtAW5_U2kfRVkDNa8d1g__2V5zjU6nfLJ1S2MoXMgRgDPeHpEehZVu2kNaSFvDUQ", "use": "sig" } ] }配置JWT Token。
选择token所在位置和token的名称。token位置支持Header、Cookie、Query参数(GET)和表单参数(POST)。如果token位置选择为Header,则还需为其指定前缀,函数计算在获取Token时,会删除此前缀。

配置JWT Claim转换。
选择透传给函数的参数所在位置、参数原始名称和参数透传给函数之后的名称。映射参数位置支持Header、Cookie、Query参数(GET)和表单参数(POST)。

结果验证
在调测工具(本文以Postman工具为例)中,根据自定义域名的JWT配置,填写自定义域名、Token等,验证是否可以正常通过自定义域名访问函数。如下图所示。
使用配置JWT认证时生成的X.509 PEM格式的Private Key作为私钥来颁发JWT Token。以下步骤以Python为例演示通过本地脚本生成Token的过程。
安装PyJWT模块。
pip install 'PyJWT>=2.0'在本地运行如下Python示例脚本生成JWT Token。
import jwt import time private_key = """ -----BEGIN PRIVATE KEY----- <使用步骤一生成的 X.509 PEM格式的private key> -----END PRIVATE KEY----- """ headers = { "alg": "RS256", "typ": "JWT" } payload = { "sub": "1234567890", "name": "John Snow", "iat": int(time.time()), # token颁发时间 "exp": int(time.time()) + 60 * 60, # 设定token有效时间为1小时 } encoded = jwt.encode(payload=payload, key=private_key.encode(), headers=headers) print("Generated token: %s" % encoded)
使用Postman工具验证自定义域名是否可以正常访问。
在函数计算控制台左侧导航栏选择,在域名管理页面获取自定义域名,填入Postman的URL位置。
在Postman的Headers配置Token参数信息。本文填写的Token示例如下。
名称
值
说明
Key
Authentication填写在JWT Token 配置中设置的参数名称。
Value
Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoiSm9uIFNub3ciLCJhZG1pbiI6dHJ1ZSwiZXhwIjo0ODI5NTk3NjQxfQ.eRcobbpjAd3OSMxcWbmbicOTLjO2vuLR9F2QZMK4rz1JqfSRHgwQVqNxcfOIO9ckDMNlF_3jtdfCfvXfka-phJZpHmnaQJxmnOA8zA3R4wF4GUQdz5zkt74cK9jLAXpokwrviz2ROehwxTCwa0naRd_N9eFhvTRnP3u7L0xn3ll4iOf8Q4jS0mVLpjyTa5WiBkN5xi9hkFxd__p98Pah_Yf0hVQ2ldGSyTtAMmdM1Bvzad-kdZ_wW0jcctIla9bLnOo-Enr14EsGvziMh_QTZ3HQtJuToSKZ11xkNgaz7an5de6PuF5ISXQzxigpFVIkG765aEDVtEnFkMO0xyPGLg填写在JWT Token 配置中设置的去除前缀Bearer和上一步生成的JWT Token。
重要请注意,请求header中JWT参数的前缀和空格需要与JWT Token 配置中设置的去除前缀内容一致,否则会导致触发器解析Token时出错并返回invalid or expired jwt错误。
单击Send,查看返回信息。

nametofunction为Claim透传给函数后的名称。