后端物联网消息队列通信【免费下载链接】emqxThe most scalable and reliable MQTT broker for AI, IoT, IIoT and connected vehicles项目地址https://gitcode.com/gh_mirrors/em/emqx点击查看免费下载本文基于 EMQX 开源仓库changes/ee/feat-16734.en.md所记录的变更展开EMQX NATS 网关新增了有序ordered的token、nkey、jwt三种内部认证方法用于缩小与原生 NATS Server 之间的认证能力差距。文章将结合 emqx_gateway_nats 应用下的配置 Schema、认证实现与测试用例完整讲解三种方法的配置方式、认证语义、底层原理与验证流程。读完本文你将能够在 EMQX 中为 NATS 网关配置与 NATS Server 对齐的令牌认证、NKey 挑战-响应认证以及完整的 JWT 信任链认证。一、变更背景补齐 NATS 网关的认证能力差距EMQX 通过协议网关Gateway机制支持 NATS 协议接入emqx_gateway_nats.erl 中通过-gateway(...)声明了名为nats的网关并指定配置 Schema 模块为emqx_nats_schema、帧处理模块为emqx_nats_frame、连接通道模块为emqx_nats_channel。原生 NATS Server 提供三类典型的认证方式token静态共享令牌客户端在CONNECT中携带auth_tokenNKey基于 Ed25519 公钥NKey与服务器下发的随机 nonce 做挑战-响应签名认证JWT基于 NATS 特有的 Operator / Account / User 三级 JWT 信任链认证并在 Account JWT 中携带撤销列表与权限声明。在此之前EMQX NATS 网关只能走通用网关认证链本次变更feat-16734在其上增加了internal_authn内部认证机制允许按顺序组合上述三种方法从而在认证模型上与 NATS Server 对齐。二、配置总览gateway.nats.internal_authn三种内部认证方法统一在网关配置的internal_authn字段下声明它是一个数组元素可以是token、nkey、jwt三种类型之一且按数组顺序依次生效即有序认证链。配置 Schema 定义在 emqx_nats_schema.erl 的fields(nats)与fields(internal_authn_token / internal_authn_nkey / internal_authn_jwt)中。一个同时启用三种方法的完整 HOCON 配置示例gateway.nats { internal_authn [ { type token token my-shared-token } { type nkey nkeys [ UDXU4RCSJMYOEHKT56T5XK4WK3M2XQYO4X3KZJ3H5PZ4JZ7KQKQA, UAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA ] } { type jwt trusted_operators [ OC5ZCOCRZ5GOU6OWL5YDZXL3Y2V7Y7VHJ2JHZ4O6KQZBJIXBZ6KQ ] resolver { type memory resolver_preload [ { pubkey AD7CYVBBPWFLGX6UGK6JXHIJNUVNDK5FSYJMPVUI3AGQXRLC7ZPAOJZ jwt eyJhbGciOiJlZDI1NTE5LW5rZXkiLCJ0eXAiOiJKV1QifQ.eyJzdWIiOiJB... } ] } } ] }说明上例中 NKey 字符串需替换为实际生成的合法 NKey见下文格式校验。internal_authn默认值为[]即不启用内部认证。除internal_authn外NATS 网关相关配置项还包括见 emqx_nats_schema.erl配置项类型默认值说明server_idstringemqx_nats_gatewayINFO 帧中的服务器标识server_namestringemqx_nats_gatewayINFO 帧中的服务器名称default_heartbeat_intervalduration30s服务器主动 PING 客户端的间隔对应 NATS keepaliveheartbeat_wait_timeoutduration5s等待客户端 PONG 的超时时间超时断开连接protocol.max_payload_sizeinteger10485761MB单条消息最大负载定义于 emqx_nats.hrlmountpointstring—主题挂载点listenersmap—TCP/SSL/WS/WSS 监听器default_heartbeat_interval与heartbeat_wait_timeout直接驱动 emqx_nats_channel.erl 中的 keepalive 定时器发送PING后启动接收定时器超时未收到PONG则返回-ERR Keepalive recv timeout并断开。三、认证方法一token静态令牌3.1 配置项{ type token token my-shared-token }Schema 定义于fields(internal_authn_token)emqx_nats_schema.erl其中type固定为tokentoken为必填且不可为空字符串。3.2 客户端携带方式与校验逻辑客户端在CONNECT帧中携带auth_token字段见 emqx_nats.hrl 中的nats_message_connect()类型。服务端处理逻辑位于 emqx_nats_authn.erl 的maybe_token_auth/5与token_authenticate/3若auth_token缺失当存在后续认证方法或网关认证链时返回skip交给下一种方法否则返回token_required错误令牌比较使用emqx_passwd:compare_secure/2做常数时间比较避免时序侧信道认证成功后将username固定为token并记录auth_method token、token_type。3.3 支持 bcrypt 哈希token字段除了明文还支持 bcrypt 哈希实现通过前缀检测$2a$、$2b$、$2y$识别 bcrypt 密文emqx_nats_authn.erl校验时调用emqx_passwd:check_pass({bcrypt, ...}, ...)。这意味着可以将令牌以 bcrypt 形式存放在配置中降低明文泄露风险。四、认证方法二nkey挑战-响应签名认证4.1 NKey 是什么NKey 是 NATS 生态中基于 Ed25519 的公开密钥标识一个 NKey 由类型前缀 32 字节 Ed25519 公钥 2 字节 CRC16-XMODEM 校验共 35 字节原始数据经 Base32 编码而成编码后为 56 个字符。前缀字符与类型对应关系在 emqx_nats_nkey.erl 中定义前缀字符类型用途UUser NKey客户端身份本方法校验的对象AAccount NKeyJWT 认证中的 AccountOOperator NKeyJWT 认证中的 Operatoremqx_nats_nkey模块提供decode_public/1仅接受U前缀、decode_public_any/1接受U/A/O三种前缀、encode_public/1、normalize/1与verify_signature/3。解码过程会校验 Base32 字符、长度56 字符与 CRC16 校验和因此配置中写入非法 NKey 会在启动校验阶段被拒绝。4.2 配置项{ type nkey nkeys [UDXU4RCSJMYOEHKT56T5XK4WK3M2XQYO4X3KZJ3H5PZ4JZ7KQKQA] }nkeys是允许接入的用户 NKey 公钥列表必填、不可为空每个元素必须是通过decode_public/1校验的合法U前缀 NKey见 emqx_nats_schema.erl。4.3 挑战-响应流程NKey 认证采用标准的挑战-响应challenge-response协议核心逻辑分布在 emqx_nats_channel.erl 与 emqx_nats_authn.erl 中下发挑战连接初始化后handle_after_init/1若启用了 nkey 或 jwt 方法服务端通过ensure_nkey_nonce/2生成 24 字节随机 nonce并在发送给客户端的INFO帧中通过maybe_add_nkey_nonce/2附带nonce字段INFO 帧字段定义见 emqx_nats.hrl客户端签名客户端用 NKey 对应的 Ed25519 私钥对 nonce 签名得到sig携带凭据CONNECT帧携带nkey与sig两个字段emqx_nats.hrl服务端校验maybe_nkey_auth_params/7→nkey_authenticate/5nkey缺失有后续方法则skip否则报nkey_requiredsig缺失报nkey_sig_requirednonce 不可用报nkey_nonce_unavailableNKey 不在nkeys白名单中报invalid_nkey调用emqx_nats_nkey:verify_signature/3执行crypto:verify(eddsa, none, Nonce, Sig, [PubKey, ed25519])验签失败报invalid_nkey_sig。认证成功后username被覆盖为规范化大写后的 NKey 公钥并记录auth_method nkey、nkey字段password置为undefined。由于 nonce 由服务端每次连接动态生成NKey 认证天然具备防重放能力客户端必须持有私钥才能通过验证。五、认证方法三jwtOperator / Account / User 信任链5.1 配置项{ type jwt trusted_operators [OC5ZCOCRZ5GOU6OWL5YDZXL3Y2V7Y7VHJ2JHZ4O6KQZBJIXBZ6KQ] resolver { type memory resolver_preload [ { pubkey AD7CYVBBPWFLGX6UGK6JXHIJNUVNDK5FSYJMPVUI3AGQXRLC7ZPAOJZ jwt eyJhbGciOiJlZDI1NTE5LW5rZXkiLCJ0eXAiOiJKV1QifQ... } ] } }JWT 方法 Schema 由fields(internal_authn_jwt)与fields(authn_jwt)、fields(jwt_resolver_memory)、fields(jwt_resolver_preload_entry)组成emqx_nats_schema.erltrusted_operators受信任的 Operator NKey 列表O前缀用于校验 Account JWT 的签发者resolver当前仅支持memory类型resolver.type固定为memoryresolver.resolver_preload预加载的 Account 列表每个条目包含pubkeyAccount NKeyA前缀必填jwt该 Account 的 JWT必填。校验规则validate_authn_jwt_required_fields/1trusted_operators与resolver.resolver_preload两者必须同时非空trusted_operators每个元素必须是O前缀的合法 Operator NKeyresolver_preload的pubkey必须是A前缀的合法 Account NKey 且不可重复。5.2 JWT 信任链验证原理这是三种方法中实现最复杂的部分完整逻辑位于 emqx_nats_authn.erl 的jwt_authenticate/6及一系列verify_*函数。客户端在CONNECT中携带jwt用户 JWT必要时同时携带nkey与sig对服务端 nonce 的签名。服务端按以下信任链层层验证格式与算法JWT 必须是标准的三段式header.payload.signaturebase64url 编码header.alg必须为ed25519-nkeyverify_jwt_token_alg/1拒绝none等弱算法User JWT 声明提取读取iss签发者可以是 Account NKey 或 Account 授权的 signing key、sub用户 NKeyU前缀、iat、exp、nbf、可选的issuer_account、nats权限声明Account JWT 解析根据 User JWT 的iss或issuer_account在resolver_preload中查找对应 Account JWT找不到报jwt_account_not_foundAccount JWT 验证校验 Account JWT 的sub必须等于预加载的pubkey且其issOperator NKey必须在trusted_operators白名单中verify_jwt_operator_trusted/2否则报jwt_untrusted_operator签名链验证用 Operator 公钥验证 Account JWT 签名用 Account 公钥或其nats.signing_keys中的授权密钥验证 User JWT 签名verify_jwt_user_issuer_allowed/3时间窗验证User JWT 与 Account JWT 都校验exp过期 →jwt_expired/account_jwt_expired与nbf未生效 →jwt_not_before/account_jwt_not_before撤销检查读取 Account JWT 的nats.revocations映射键为 User NKey 或*撤销全部值为撤销时间戳若 User JWT 的iat不晚于撤销时间则拒绝jwt_revoked——这使管理员可以无需重新签发密钥即可吊销已泄漏的用户凭据nonce 签名校验verify_jwt_nonce_signature/4CONNECT必须携带对服务端 nonce 的签名sig且签名的 NKey 必须与 User JWT 的sub一致jwt_nkey_mismatch从而将 JWT 与持证者确实持有私钥绑定防止 JWT 被离线窃取后冒用。认证成功后username被设置为 JWTsub对应的 User NKeyauth_method jwtauth_expire_at取 User JWT 与 Account JWTexp中较早的一个emqx_nats_authn.erl供连接过期管理使用。5.3 JWT 权限投影从 NATS subject 到 EMQX ACLUser JWT 中可通过nats.pub/nats.sub或兼容的旧字段permissions.pub/permissions.sub声明主题级权限每个声明包含allow与deny的 NATS subject 列表emqx_nats_authn.erl。这些权限在连接建立后被投影到 ClientInfo 的jwt_permissions字段并由 emqx_nats_channel.erl 的authorize_publish/2、check_sub_acl/2在发布与订阅时执行deny 优先主题先匹配 deny 列表命中即拒绝allow 匹配未命中 deny 时若 allow 列表为空则默认允许allow_empty否则必须命中 allow 列表JWT 权限判定通过后仍会继续走 EMQX 网关 ACL 授权emqx_gateway_ctx:authorize/4即 JWT 权限与既有授权链叠加生效。5.4 配置期校验JWT 配置不仅在建连时验证配置写入时就会执行静态校验validate_jwt_config/1见 emqx_nats_authn.erl逐一检查resolver_preload中每个条目的格式并尝试用对应 Operator 公钥验证 Account JWT 的签名与nats.revocations结构错误信息会指明具体是第几个条目、哪个 Account、哪类错误方便快速定位配置问题。六、有序认证链顺序、回退与优先级internal_authn数组的顺序就是认证尝试顺序这是本次变更的关键语义文档原文中的 ordered。核心实现在 emqx_nats_authn.erl 的do_authenticate/5do_authenticate([Method | Rest], ConnParams, ConnInfo, ClientInfo, Authn) - HasFallback Rest / [] orelse gateway_auth_enabled(Authn), case maybe_auth(Method, ConnParams, ConnInfo, ClientInfo, HasFallback) of {ok, NClientInfo} - {ok, NClientInfo}; % 当前方法通过 {skip, NClientInfo} - do_authenticate(Rest, ...); % 无凭据/方法禁用 → 尝试下一个 {error, Reason} - {error, {method_type(Method), Reason}} % 有凭据但校验失败 → 直接拒绝 end; do_authenticate([], _ConnParams, _ConnInfo, ClientInfo, _Authn) - {continue, ClientInfo}. % 全部跳过 → 交给网关认证链需要区分的三种结果结果触发条件行为{ok, ...}当前方法校验通过立即放行后续方法不再执行{skip, ...}该方法未启用或客户端未携带对应凭据且存在后续方法/网关认证链继续尝试下一种方法{error, ...}客户端携带了凭据但校验失败如令牌错误、验签失败、JWT 过期立即拒绝并返回对应-ERR不回退这一有凭据必校验、无凭据才回退的设计避免了安全绕过例如同时配置 token 与 jwt 时携带了错误auth_token的客户端不会因为 token 失败而溜到JWT 方法也不会被放行对应测试t_authenticate_token_priority_over_jwt。当所有内部方法都返回skip时若同时配置了网关级authenticationgateway.nats.authentication存在则回退到通用网关认证链emqx_gateway_ctx:authenticate/2见 emqx_nats_channel.erl否则依据安全 Profile 策略authn_not_configured决定放行allow或拒绝deny——这与 EMQX 的 legacy / hardened 安全等级联动。另外Schema 层会拒绝同一类型重复配置duplicate_authentication_method_type保证链上每种方法至多出现一次emqx_nats_schema.erl。七、完整连接认证时序将上述逻辑串起来一次带内部认证的 NATS 连接时序如下以同时启用三种方法为例NATS Client EMQX NATS Gateway │ │ │ TCP/TLS 建立 │ │───────────────────────────────────────────│ │ │ handle_after_init: │ │ 生成 24 字节 noncenkey/jwt 启用时 │ INFO {auth_required:true, nonce:..., │ │ server_id, max_payload, ...} │ │───────────────────────────────────────────│ │ CONNECT { │ │ auth_token, │ ① token 方法常数时间比较 │ nkey, sig sign(nonce), │ ② nkey 方法Ed25519 验签 白名单 │ jwt, nkey, sig │ ③ jwt 方法信任链 时间 撤销 验签 │ } │ │───────────────────────────────────────────│ │ │ 按 internal_authn 顺序执行 │ │ 成功 → OK / 失败 → -ERR 断开其中INFO帧的auth_required字段由is_auth_required/2计算只要启用了任一内部方法、配置了网关认证链或安全策略要求未配置认证时拒绝连接该字段即为true客户端据此决定是否携带凭据。INFO 帧的完整字段定义见 emqx_nats.hrlinfo_frame/1的实现见 emqx_nats_channel.erl。八、敏感配置的脱敏回填token字段与 JWT 方法中resolver_preload的jwt字段属于敏感信息。通过 Dashboard 或 HTTP API 读取配置时会以掩码如******呈现更新配置时Schema 的deobfuscate/2emqx_nats_schema.erl会把掩码值与旧配置中的真实值匹配并回填规则包括掩码字段必须能在旧配置中找到唯一的同类型方法/同 pubkey 条目否则报masked_secret_without_matching_old_value拒绝更新JWT 预加载条目的匹配基于 pubkey 的身份支持大小写归一化掩码条目可被重新排序重复方法类型、重复 pubkey 均被拒绝。对应的行为均有测试用例覆盖如t_deobfuscate_internal_authn、t_deobfuscate_reordered_jwt_preload。九、测试验证本次变更的认证逻辑在 emqx_nats_authn_SUITE.erl 中有系统性的测试覆盖且该套件在legacy与hardened两种安全 Profile 下分别运行init_per_group/2设置安全 Profile确保认证必需性在不同安全等级下行为一致。关键测试点包括有序语义t_authenticate_order_from_internal_authn验证方法排列顺序决定认证结果——token 在前时错误令牌直接失败jwt 在前时优先走 JWT 成功优先级与回退t_authenticate_token_priority_over_jwt、t_authenticate_token_priority_over_nkey、t_authenticate_token_fallback_to_jwt、t_authenticate_nkey_fallback_and_validation覆盖有凭据必校验、无凭据才回退的组合场景tokent_authenticate_token_plain_success、t_authenticate_token_bcrypt_success覆盖明文与 bcrypt 两种令牌nkeyt_authenticate_nkey_success验证用户名被覆盖为规范化 NKey、auth_expire_at为undefinedJWTt_authenticate_jwt_time_validation、t_authenticate_jwt_account_claims_validation、t_authenticate_jwt_signature_and_trust_chain_validation覆盖过期/未生效/撤销按用户与按*/弱算法拒绝/签名篡改/Account 缺失/Operator 不受信等场景noncet_ensure_and_publish_nkey_nonce验证 nonce 仅生成一次、长度为 24 字节并正确注入 INFO 帧配置脱敏t_deobfuscate_*系列覆盖掩码回填、重复类型拒绝等 Schema 校验路径。此外emqx_nats_protocol_SUITE.erl、emqx_nats_channel_SUITE.erl等测试覆盖了网关的协议帧解析与连接通道行为。十、总结本次feat-16734变更为 EMQX NATS 网关注入了与原生 NATS Server 对齐的三种内部认证方法token简单的共享令牌认证支持明文与 bcrypt 哈希常数时间比较防时序攻击nkey基于 Ed25519 与每次连接动态 nonce 的挑战-响应认证天然防重放公钥白名单管理jwt完整实现 Operator / Account / User 三级信任链、签发密钥授权、按用户/全局撤销、时间窗校验与 JWT 主题权限投影到 EMQX ACL并支持配置期静态校验。三者以有序数组组合成认证链客户端携带哪类凭据就校验哪类方法无凭据才逐级回退最终可回退到既有网关认证链或由安全 Profile 策略兜底。对于希望以 NATS 生态标准方式管理客户端身份的 EMQX 用户可直接沿用 NATS Server 的 token、nsc工具链生成的 NKey 与 JWT 体系接入显著降低迁移成本。参考资料变更记录changes/ee/feat-16734.en.md网关入口emqx_gateway_nats.erl配置 Schemaemqx_nats_schema.erl认证实现emqx_nats_authn.erlNKey 编解码与验签emqx_nats_nkey.erl连接通道与认证集成emqx_nats_channel.erl协议操作与消息类型定义emqx_nats.hrl帧解析emqx_nats_frame.erl认证测试套件emqx_nats_authn_SUITE.erl赞分享后端物联网消息队列通信【免费下载链接】emqxThe most scalable and reliable MQTT broker for AI, IoT, IIoT and connected vehicles项目地址https://gitcode.com/gh_mirrors/em/emqx点击查看免费下载相关推荐Activepieces Managed Auth 深度解析:基于 JWT 的嵌入式认证与外部 Token 交换机制Activepieces Managed Auth 深度解析:基于 JWT 的嵌入式认证与外部 Token 交换机制 Managed Auth 托管认证 是 A工作流自动化低代码AI 应用人工智能AI AgentMCP 服务后端前端PanSou认证系统深度剖析JWT Token安全机制与多用户配置PanSou认证系统深度剖析JWT Token安全机制与多用户配置 PanSou作为一款高性能的网盘资源搜索API服务其 JWT Token认证系统 在企业后端搜索引擎网页爬虫Sa-Token OAuth2.0 安全认证框架深度解析Sa Token OAuth2.0 安全认证框架深度解析 在当今微服务架构盛行的时代安全认证已成为系统设计中不可或缺的一环。Sa Token作为一款轻量级Ja后端认证鉴权创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考