JWT 认证
JWT 认证是基于 Token 的鉴权机制,不依赖服务端保留客户端的认证信息或者会话信息,在持有密钥的情况下可以批量签发认证信息,是最简便的认证方式。
提示
Serverless 部署不支持 JWT 认证。
JWT 认证原理
客户端使用用户名或密码字段携带 JWT(取决于模块配置),发起连接时 EMQX Platform 使用配置中的密钥、证书进行解密,如果能成功解密则认证成功,否则认证失败。
如果签名验证成功,JWT 认证器将继续检查声明。JWT 认证器会根据这些声明如 iat
(签发时间)、nbf
(不早于)和 exp
(过期时间)来主动检查 JWT 的有效性。还可以指定额外的自定义声明进行认证。只有当签名和声明的认证都成功时,客户端才被授权访问。
默认配置下启用 JWT 认证后,你可以通过任意用户名+以下密码进行连接,即通过默认的密钥字段 emqxsecret
做验证:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJFTVFYIENsb3VkIiwiaWF0IjoxNTE2MjM5MDIyfQ.-k9Ggc6L_Jxq4uUf9xwdJpwRrS3PquL-JZKtAJoOvBo
上述 JWT Token 仅做测试使用,您可以使用适当的工具生成适合您业务需求的 JWT Token,参考如何生成 JWT。
如何生成 JWT
本节将逐步介绍如何生成用于 EMQX 客户端认证的有效 JWT。
前提条件
- 一个密钥(HMAC 算法使用)或私钥(RSA/ECDSA 使用)
- 一个生成 JWT 的工具或代码库(例如 jwt.io、jjwt、mkjwk、Python、Node.js)
- 知道 EMQX 所期望的签名算法(如
HS256
、RS256
等)
JWT 结构
JWT 由三部分组成:
JWT = base64UrlEncode(Header) + "." + base64UrlEncode(Payload) + "." + Signature
Header(头部):用于描述签名算法和 token 类型,例如:
json{ "alg": "HS256", "typ": "JWT" }
Payload(负载):包含声明信息(即用户或设备的相关数据),例如:
json{ "username": "emqx_user", "exp": 1719830400, "client_attrs": { "role": "admin", "sn": "device-001" } }
Signature(签名):用于校验 token 是否被篡改,通过对 header 和 payload 签名生成。
生成步骤
定义 JWT Header。例如(使用 HMAC SHA-256 算法):
json{ "alg": "HS256", "typ": "JWT" }
若使用 RSA/ECDSA 算法,请将
"alg"
替换为RS256
、ES256
等。定义 JWT Payload。Payload 中包含 EMQX 使用的声明字段,例如:
json{ "sub": "mqtt_client", // Subject:可选,用于标识 "username": "emqx_user", // 可选:EMQX 可配置绑定验证 "clientid": "client_123", // 可选:用于绑定特定客户端 ID "exp": 1719830400 // 必填:过期时间(Unix 时间戳) }
注意:
exp
是必需字段,否则 EMQX 可能拒绝该 JWT。- 如配置验证,需在 JWT 中提供
username
和/或clientid
。 - 你还可以添加自定义字段,如
acl
、client_attrs
等。
对 Header 和 Payload 进行 Base64Url 编码。可使用手动方式或相关库完成。
签名 JWT。使用你的密钥或私钥对数据进行签名:
- HMAC 示例(如
HS256
):HMACSHA256(base64Url(header) + "." + base64Url(payload), secret)
- RSA/ECDSA 示例(如
RS256
):使用私钥和指定算法生成签名。
- HMAC 示例(如
组装 JWT:将编码后的 Header、Payload、Signature 用点号
.
拼接:<header>.<payload>.<signature>
(可选)验证 JWT:建议使用 jwt.io 或开发工具验证 JWT 的有效性和结构。
使用 Python (pyjwt
) 示例
import jwt
import datetime
secret = "your_shared_secret"
payload = {
"username": "emqx_user",
"exp": datetime.datetime.utcnow() + datetime.timedelta(hours=1)
}
token = jwt.encode(payload, secret, algorithm="HS256")
print(token)
如使用 RS256
,请将 secret
替换为私钥,并指定算法为 RS256
。
最终结果
你现在已经获得一个签名后的 JWT,可根据 EMQX 的配置,将其放入 MQTT CONNECT
报文的 username 或 password 字段中进行认证。
有关生成更复杂 JWT 用例的详细指南,请参考博客文章:JWT 认证原理与 JWKS Endpoint 构建指南。
权限列表
如果 JWT 中包含 acl
字段,EMQX 将根据该字段指定的权限对客户端进行访问控制。 详情请参考权限列表(ACL)。
客户端属性
从 EMQX v5.7.0 版本开始,您可以在 JWT Payload 中使用可选的 client_attrs
字段设置客户端属性。请注意,键和值都必须是字符串类型。
示例:
{
"exp": 1654254601,
"username": "emqx_u",
"client_attrs": {
"role": "admin",
"sn": "10c61f1a1f47"
}
}
认证配置
在部署中点击 访问控制 -> 客户端认证 -> 扩展认证,选择 JWT 认证,点击配置认证。
您可根据如下说明完成相关配置:
如验证方式选择 JWT 时:
JWT 来自于:指定客户端连接请求中 JWT 的位置;可选值:
password
、username
(分别对应于 MQTT 客户端CONNECT
报文中的Password
和Username
字段)加密方式:指定 JWT 的加密方式,可选值:
hmac-based
、public-key
;如选择
hmac-based
,即 JWT 使用对称密钥生成签名和校验签名(支持 HS256、HS384 和 HS512 算法),还应配置:- Secret:用于校验签名的密钥,与生成签名时使用的密钥相同。
- Secret 使用 Base64 编码:配置 EMQX 在使用
Secret
校验签名时是否需要先对其进行 Base64 解密;可选值:True、False,默认值:False。
如选择
public-key
,即 JWT 使用私钥生成签名,同时需要使用公钥校验签名(支持 RS256、RS384、RS512、ES256、ES384 和 ES512 算法),还应配置:- Public Key:指定用于校验签名的 PEM 格式的公钥。
过期后断开连接:配置是否在 JWT 过期后断开客户端连接,默认启用。
Payload:添加自定义的 Claims 检查;用户需要在 Claim 和 Expected Value 分别添加键和对应的值,支持使用
${clientid}
和${username}
占位符。其中键用于查找 JWT 中对应的 Claim,值则用于与 Claim 的实际值进行比较。
如验证方式选择 JWTS:
除上述配置外,还应配置:
- JWKS Endpoint:指定 EMQX 查询 JWKS 的服务器端点地址,该端点需要支持 GET 请求,并且返回符合规范的 JWKS。
- JWKS 刷新间隔:指定 JWKS 的刷新间隔,也就是 EMQX 查询 JWKS 的间隔。默认值:300 单位为秒(s)。 点击创建完成相关配置。
- 请求头:指定必须包含在对 JWKS 服务器请求中的任何其他 HTTP 请求头。添加这些 HTTP 请求头可以确保对 JWKS 服务器的请求根据服务器的要求进行正确格式化。此配置允许用户添加键值对,例如:
- 键:
Accept
- 值:
application/json
- 键:
TIP
- 如果当前部署为专有版,需创建 VPC 对等连接,服务器地址填写内网地址。
- 如果当前部署为 BYOC 版,需在您的公有云控制台中创建 VPC 对等连接,具体请参考创建 BYOC 部署 - VPC 对等连接配置 章节。服务器地址填写内网地址。
- 若提示 Init resource failure! 请检查服务器地址是否无误、安全组是否开启。