后端物联网消息队列通信【免费下载链接】emqxThe most scalable and reliable MQTT broker for AI, IoT, IIoT and connected vehicles项目地址https://gitcode.com/gh_mirrors/em/emqx点击查看免费下载导读EMQX 从 v5.x 起支持在认证链Authentication Chain中为每个认证器Authenticator配置前置条件Precondition表达式。本文基于 changes/ee/feat-14976.en.md 的变更记录展开介绍如何在认证器中通过 Variform 表达式按客户端信息如监听器、Zone、用户名等选择性调用认证器从而避免不必要的认证请求。读完本文你将掌握precondition配置项的语法、可用变量、真实配置示例以及它在源码中的编译、渲染与执行机制。功能背景与核心价值EMQX 的认证Authenticationauthn采用认证链机制多个认证器按顺序排列逐个尝试对客户端进行身份验证。在默认情况下链上的每个认证器都会被依次调用直到某个认证器返回成功或全部失败。引入 precondition前置条件后每个认证器可以附带一个 Variform 条件表达式。只有当该表达式求值为字符串true时对应的认证器才会被真正调用否则该认证器被跳过直接进入链上的下一个认证器。这带来了两个直接收益避免不必要的认证请求例如将 HTTP 认证器限定在tcp:default监听器将 PostgreSQL 认证器限定在ssl:default监听器从而减少跨网络的后端请求实现按场景分流同一认证链可以按客户端来源、TLS 属性、用户名/密码特征等维度路由到不同的认证后端。该能力由 EMQX 认证模块 apps/emqx_auth 实现涉及配置 Schema、认证链执行逻辑与 Variform 表达式引擎三部分。配置项说明precondition字段在认证器Authenticator配置中新增了可选字段precondition。它定义在认证链公共字段中见 apps/emqx_auth/src/emqx_authn/emqx_authn_schema.erl#L200-L213类型binary()字符串表达式默认值空字符串等价于未配置表示该认证器无条件被调用语义一个 Variform 表达式使用客户端信息作为预绑定变量求值表达式求值结果必须为字符串true认证器才会被调用求值为任何其他值则跳过该认证器。可用变量根据 rel/i18n/emqx_authn_schema.hocon#L168-L194 中的字段描述表达式可用的预绑定变量来源于客户端信息包括变量含义username客户端用户名password客户端密码clientid客户端 IDclient_attrs.*客户端属性cert_common_name客户端 TLS 证书的 subject 字段cert_subject客户端 TLS 证书的 CNCommon NamepeersniTLS 客户端发送的 SNIServer Name Indicationlistener监听器 ID例如tcp:defaultzone客户端关联的配置 Zone常用表达式示例文档 rel/i18n/emqx_authn_schema.hocon#L186-L192 给出的官方示例仅当客户端从监听器ssl:letsencrypt接入时才调用该认证器str_eq(listener, ssl:letsencrypt)当用户名为空时跳过该认证器not(is_empty_val(username))仅当密码存在且 Zone 为zone1时调用iif(is_empty_val(password), false, str_eq(zone, zone1))这些内置函数如str_eq、is_empty_val、iif、not的行为可在 Variform 表达式引擎的单元测试 apps/emqx_utils/test/emqx_variform_tests.erl#L247-L253 与 apps/emqx_utils/test/emqx_variform_tests.erl#L384-L386 中验证例如str_eq(a, a)求值为{ok, true}str_eq(a, b)求值为{ok, false}iif(str_eq(a,1),2,3)在a 1时求值为2否则为3。配置示例按监听器分流认证器变更记录 changes/ee/feat-14976.en.md 中给出了典型场景对通过tcp:default接入的客户端触发 HTTP 认证器对通过ssl:default接入的客户端触发 PostgreSQL 认证器。在 HOCON 配置文件中可以在认证链authentication下为每个认证器添加preconditionauthentication [ { mechanism password_based backend http method post url http://127.0.0.1:8080/auth precondition str_eq(listener, tcp:default) enable true }, { mechanism password_based backend postgresql server 127.0.0.1:5432 database mqtt username emqx password secret precondition str_eq(listener, ssl:default) enable true } ]运行效果通过tcp:default监听器接入的客户端HTTP 认证器前置条件满足 → 触发 HTTP 认证请求PostgreSQL 认证器前置条件不满足 → 被跳过不产生任何 PostgreSQL 查询通过ssl:default监听器接入的客户端行为相反仅 PostgreSQL 认证器被调用两个监听器的客户端共用同一个认证链但认证后端完全隔离。源码实现解析Schema 定义precondition作为认证器公共字段与enable并列注册见 apps/emqx_auth/src/emqx_authn/emqx_authn_schema.erl#L209-L213common_fields() - [ {enable, fun enable/1}, {precondition, precondition()} ].编译期表达式预编译创建认证器时配置中的 precondition 字符串会先经emqx_variform:compile/1编译为内部表达式预编译可提前发现语法错误编译失败时返回bad_precondition_expression错误apps/emqx_auth/src/emqx_authn/emqx_authn_chains.erl#L1068-L1082 中的compile_precondition/1与do_compile_precondition/1undefined与空二进制都被视为无前置条件编译结果为undefined创建认证器的入口 apps/emqx_auth/src/emqx_authn/emqx_authn_chains.erl#L1028-L1035 与更新认证器的 apps/emqx_auth/src/emqx_authn/emqx_authn_chains.erl#L726-L752 都会执行编译并把编译结果存入#authenticator{precondition ...}记录。运行期条件检查与跳过语义认证链按顺序执行认证器时会先检查 preconditionapps/emqx_auth/src/emqx_authn/emqx_authn_chains.erl#L923-L932 的check_precondition/2调用emqx_variform:render(Precondition, Credential)求值结果恰好为二进制true时返回{ok, true}apps/emqx_auth/src/emqx_authn/emqx_authn_chains.erl#L934-L952 的authenticate_with_provider/2依据检查结果分三种情况处理{ok, true}调用do_authenticate_with_provider/2真正执行后端认证{error, _}表达式本身求值出错如引用了不存在的变量记为precondition_error并按后端失败处理{ok, Other}表达式求值成功但结果不是true记为precondition_not_met并返回ignoreapps/emqx_auth/src/emqx_authn/emqx_authn_chains.erl#L903-L906ignore结果不会终止认证链而是继续尝试链上的下一个认证器{stop, _}则终止。因此precondition 不满足的认证器对认证链而言等价于未匹配nomatch 语义既不会触发后端请求也不会中断认证流程。安全基线Hardened Profile下的组合在加固安全基线hardened security profile下precondition 与ignore_backend_failures语义可以组合使用形成按条件跳过 后端失败忽略的弹性认证链。相关测试见 apps/emqx_auth/test/emqx_authn/emqx_authn_chains_SUITE.erl#L727-L762。实战验证JWT 与密码认证的混合链测试套件 apps/emqx_auth/test/emqx_authn/emqx_authn_chains_SUITE.erl#L842-L856 演示了一个典型用法在同一认证链中先创建带前置条件is_jwt(password)的 JWT 认证器再创建内置数据库built_in_database的密码认证器{ok, _} ?AUTHN:create_authenticator(ListenerID, #{ mechanism jwt, enable true, precondition is_jwt(password) }), {ok, _} ?AUTHN:create_authenticator(ListenerID, #{ mechanism password_based, backend built_in_database, enable true }).测试验证的行为apps/emqx_auth/test/emqx_authn/emqx_authn_chains_SUITE.erl#L735-L761当密码是 JWT 时前置条件满足 → 调用 JWT 认证器当密码不是 JWT 时前置条件不满足 → 跳过 JWT 认证器回落到密码认证器当完全没有密码时表达式求值为 false非错误→ 同样跳过继续后续认证器。这正体现了 precondition 的核心价值把是否适用的判断从认证逻辑中剥离出来交给可声明、可预编译的表达式让认证链更简洁、更高效。注意事项precondition表达式的求值结果是字符串true而非布尔值true编写表达式时需注意函数的返回值形态表达式求值失败如变量不存在会被视为认证失败而不是跳过与表达式结果为 false 时跳过语义不同参见 apps/emqx_auth/src/emqx_authn/emqx_authn_chains.erl#L938-L944该配置同样适用于认证授权authz模块其 Schema 中也有precondition字段见 apps/emqx_auth/src/emqx_authz/emqx_authz_schema.erl实现思路一致通过 Dashboard / HTTP API 创建认证器时同样可以在请求体中携带precondition字段通过 Dashboard 界面配置时该项位于认证器的Precondition设置中。延伸阅读认证链核心实现apps/emqx_auth/src/emqx_authn/emqx_authn_chains.erl认证器配置 Schemaapps/emqx_auth/src/emqx_authn/emqx_authn_schema.erl字段说明与示例rel/i18n/emqx_authn_schema.hoconVariform 表达式引擎apps/emqx_utils/src/emqx_variform.erl 及其测试 apps/emqx_utils/test/emqx_variform_tests.erl功能变更记录changes/ee/feat-14976.en.md赞分享后端物联网消息队列通信【免费下载链接】emqxThe most scalable and reliable MQTT broker for AI, IoT, IIoT and connected vehicles项目地址https://gitcode.com/gh_mirrors/em/emqx点击查看免费下载相关推荐EMQX 的 is_jwt 前置条件函数在认证链中优雅分流 JWT 与传统凭据客户端EMQX 的 is_jwt 前置条件函数在认证链中优雅分流 JWT 与传统凭据客户端 导读 本文围绕 EMQX 6.2.3 新增的 is_jwt value后端物联网消息队列通信CephFS 挂载前置条件指南客户端选择、CephX 认证与配置文件准备CephFS 挂载前置条件指南客户端选择、CephX 认证与配置文件准备 本指南以 Ceph 官方文档 Mount CephFS: Prerequisites存储分布式文件系统对象存储后端高可用EMQX 授权源前置条件Precondition基于 Variform 表达式的动态鉴权路由EMQX 授权源前置条件Precondition基于 Variform 表达式的动态鉴权路由 导读 EMQX 的授权Authorization/ACL后端物联网消息队列通信创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
