十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

EMQX Dashboard 用户 API 修复深度解析:默认管理员备注编辑报错问题与 scope 隐式继承语义

EMQX Dashboard 用户 API 修复深度解析:默认管理员备注编辑报错问题与 scope 隐式继承语义 后端物联网消息队列通信【免费下载链接】emqxThe most scalable and reliable MQTT broker for AI, IoT, IIoT and connected vehicles项目地址https://gitcode.com/gh_mirrors/em/emqx点击查看免费下载本文基于 EMQX 开源仓库 changes/ee/fix-18009.en.md 变更记录结合 emqx_dashboard_api.erl 与 emqx_dashboard_admin.erl 源码实现系统讲解 Dashboard 用户 API/api/v5/users在仅编辑默认管理员备注时曾经报错的原因、修复方案以及修复后引入的scope 隐式继承implicit scopes语义。读完本文你将理解 EMQX Dashboard 用户权限模型中的unset哨兵值、三态写入意图keep/unset/{set, L}设计以及如何正确地对管理员账号执行读-改-写read-modify-write操作而不破坏其前向兼容的权限继承关系。一、变更背景一个典型的读-改-写失败场景在 EMQX 5.x 引入 Dashboard 用户细粒度 scope权限范围功能之后GET /api/v5/users/:username返回的响应中包含了scopes字段。与此同时为了防止读改写操作将角色的隐式默认权限冻结为显式列表GET接口刻意返回的是存储态的 scope 值而不是展开后的有效权限集合。问题正出在这里对于通过dashboard.default_username配置创建的默认管理员break-glass 账户其持久化记录中没有scopes字段因此GET返回的scopes值是哨兵字符串unset而运行时授权路径则会把角色隐式默认集对全局管理员而言是GENERIC_SCOPES LOGIN_ONLY_SCOPES即通用 scope 4 个登录专用 scope当作其有效权限。当用户尤其是 Dashboard Web 控制台执行读-改-写流程——先GET拿到完整数据仅修改description备注字段再把整个对象PUT回去时旧版本代码无法把展开后的完整 scope 列表识别为无显式 scope于是校验失败PUT请求返回 400 错误仅编辑备注这一普通操作无法完成即便部分路径放行写回时也可能把隐式默认集固化为显式列表导致用户失去前向兼容能力——未来角色默认 scope 扩充时该用户无法自动获得新增权限。本变更issue #17931 相关修复changelog 编号 fix-18009正是为了解决这一问题让用户 API 接受与角色隐式默认集等价的 scope 列表以及unset哨兵值并将其视为无显式 scope。二、核心修复三态写入意图write intent模型修复的核心集中在 emqx_dashboard_api.erl 中write_scope_intent/2函数。它把客户端提交的scopes值归一化为三种存储意图写入意图触发条件存储行为keep请求体完全省略scopes字段undefined保持已持久化的 scope 不变例如仅改备注时unset提交unset原子、二进制unset哨兵或一个与角色默认集相等无序集合比较的列表不写scopes字段scopes_of/1保持undefinedGET继续返回unset{set, L}其他任何显式列表原样存储列表L随后由下游校验把关该函数实现位于 emqx_dashboard_api.erlwrite_scope_intent(_Role, undefined) - keep; write_scope_intent(_Role, unset) - unset; write_scope_intent(_Role, unset) - unset; write_scope_intent(Role, Scopes) when is_list(Scopes) - case is_role_default_scopes(Role, Scopes) of true - unset; false - {set, Scopes} end; write_scope_intent(_Role, Other) - {set, Other}.其中与角色默认集相等的判断采用无序集合比较lists:usort/1排序后对比因此客户端无论以何种顺序回传 scope 列表都能被正确识别%% Order-insensitive set comparison of a write scope list against the %% roles implicit default (role_default_scopes/1). The dashboard may %% send the scopes in any order. is_role_default_scopes(Role, Scopes) - Default emqx_dashboard_admin:role_default_scopes(Role), lists:usort(Scopes) : lists:usort(Default).说明write_scope_intent/2的定义与实现均位于 emqx_dashboard_api.erl。三态模型完整贯穿POST /users创建与PUT /users/:username更新两条写入路径。三、API 契约请求与响应的 scope 形态本次修复同步完善了 OpenAPI schema 定义明确规定了请求与响应中scopes字段的合法形态见 emqx_dashboard_api.erl请求形态scopes_requestunset哨兵 与 二进制字符串数组 的联合类型。注释明确指出接受与响应相同的形态以便读-改-写可以原样往返该值——即显式 scope 名数组或unset哨兵解析为原子unset同时容忍二进制unset。与角色默认集相等的列表和unset哨兵在写入时一律视为无显式 scope。响应形态scopes_response同样为联合类型但额外说明scopes unset哨兵只可能出现在从旧版本升级而来的遗留记录上scope 功能引入之前的版本对应 #17235 变更。POST与 SSO 预置路径都会在创建时实体化角色默认 scope因此新创建的用户永远不会以unset状态出现。有效权限响应effective_scopes_response始终是具体列表——角色默认集会被展开因此unset哨兵绝不会出现在此字段中。该字段用于GET /current_user端点emqx_dashboard_api.erl 中的current_user_fields/0报告当前用户实际拥有的权限。对应的 HTTP 端点及所需 scope 权限emqx_dashboard_api.erl端点方法所需 scope/usersGET / POSTuser_management/users/:usernamePUT / DELETEuser_management/users/:username/mfa—mfa_management/users/:username/change_pwdPOST公开deprecated 自服务 shim/current_user/*—公开自服务主体即调用者/user_scopesGET公开静态目录端点四、默认管理员的 break-glass 保护与修复后的放行逻辑默认管理员由dashboard.default_username配置指定见 emqx_dashboard_admin.erl是一个 break-glass 账户受多重保护不可删除、不可降级、不可被赋予显式 scope 列表以保证集群即使在其他管理员被误限制或误删除时仍可恢复。本次修复对is_default_admin_modification/3的判定逻辑做了关键调整emqx_dashboard_api.erlis_default_admin_modification(Username, Role, Intent) - case is_default_admin(Username) of false - ok; true - case {Role, Intent} of {?ROLE_SUPERUSER, keep} - ok; {?ROLE_SUPERUSER, unset} - ok; {?ROLE_SUPERUSER, {set, _}} - {error, The default administrator cannot have an explicit scope list; it always holds the full catalog. }; {_OtherRole, _} - {error, The default administrator role cannot be changed. } end end.即keep字段省略与unset哨兵或角色默认等价列表都被视为无显式 scope而放行——这正是读-改-写流程往返 GET 返回的完整目录能够成功的关键。只有{set, _}与角色默认集不同的列表才被拒绝角色被修改为其他角色同样被拒绝。空列表[]自限制场景也属于{set, _}同样被拒对应测试t_default_admin_cannot_be_set_to_empty_scopes。五、升级自愈启动时清除被固化的默认管理员 scope除了 API 写入路径本次修复还补齐了升级场景的自愈能力。早期版本在引导bootstrap时会给默认管理员播种一份显式的角色默认列表升级到本版本后这些被冻结的 scope 需要在启动时被清除使集群恢复隐式前向兼容的 scope 集合。该逻辑位于 emqx_dashboard_admin.erl%% Earlier releases seeded the default admin with an explicit role-default %% list at bootstrap; clear it on boot so upgraded clusters regain the %% implicit (forward-compatible) scope set. ensure_default_admin_scopes_unset(Username) - case scopes_of(Username) of undefined - ok; _Explicit - _ clear_user_scopes(Username), ok end.该函数在add_default_user/2检测到默认管理员已存在时被调用emqx_dashboard_admin.erl确保升级后的集群中默认管理员始终处于unset隐式继承状态。六、运行时授权scopes_of与effective_scopes_of的分工理解整个修复还需要区分存储态与有效态两个概念scopes_of/1读取持久化的显式 scope 列表无显式字段时返回undefined。effective_scopes_of_admin/1运行时授权实际使用的有效集合。当scopes_of/1返回undefined时回退到role_default_scopes(Role)emqx_dashboard_admin.erl。角色默认集由role_default_scopes/1计算emqx_dashboard_admin.erl角色默认 scope 集全局管理员administratorGENERIC_SCOPES LOGIN_ONLY_SCOPES命名空间管理员ns:xxx::administratorNS_ADMIN_ALLOWED_SCOPES受限子集其他角色如viewerGENERIC_SCOPES其中各 scope 宏定义于 emqx_api_key_scopes.hrlGENERIC_SCOPES10 个API Key 与登录用户通用connections、publish、data_integration、access_control、gateways、monitoring、cluster_operations、system、audit、licenseLOGIN_ONLY_SCOPES4 个仅登录用户可持有user_management、mfa_management、sso_management、api_key_management。正是存储态保持undefined/ 有效态由角色默认集动态计算的双层设计让默认管理员能够在未来版本扩充角色默认 scope 时自动获得新权限而非被冻结在一份陈旧的显式列表上。这也是本次修复反复强调forward-compatible implicit scopes的根本原因。七、测试验证读-改-写往返与保护规则全覆盖仓库中的测试套件 emqx_dashboard_user_scopes_SUITE.erl 对该修复提供了完整的回归覆盖核心用例包括1. 仅编辑备注 回传完整列表 → 200 且不固化t_default_admin_note_only_edit_full_list测试源码对默认管理员PUT回传role_default_scopes(?ROLE_SUPERUSER)的完整列表并修改description断言响应为 200、description已更新、scopes仍为unset、且底层scopes_of/1保持undefined——即权限未被固化。2. 回传unset哨兵 → 原样往返t_default_admin_put_unset_sentinel测试源码PUT scopes: unset成功且保持unset状态。3. 乱序回传完整列表 → 仍识别为 unsett_default_admin_put_full_list_shuffled测试源码将完整目录反转后提交验证无序集合比较逻辑。4. 真正不同的列表 → 仍然拒绝t_default_admin_put_different_list_rejected测试源码提交完整目录的严格子集如仅user_management断言返回 400 NOT_ALLOWED。5. 保护规则系列t_default_admin_cannot_be_demoted不可降级、t_default_admin_cannot_have_explicit_scopes不可显式赋权、t_default_admin_cannot_be_set_to_empty_scopes空列表同样拒绝、t_default_admin_description_can_be_updated仅改备注允许、t_default_admin_cannot_be_deleted不可删除、t_default_admin_protection_does_not_apply_to_sso_usersSSO 用户不适用默认管理员保护。6. 启动自愈t_default_admin_bootstrap_unset_scopes与t_default_admin_boot_clears_frozen_scopes测试源码验证了早期版本固化在默认管理员上的 scope 会在启动时被清除回unset。此外测试还覆盖了普通用户的相关语义t_regular_user_round_trip_full_list_stays_unset普通用户往返完整目录保持 unset、t_regular_user_put_unset_clears_explicitPUT unset清除已显式化的列表、t_post_create_unset_sentinelPOST 创建时用unset哨兵创建无显式 scope 用户、以及t_legacy_record_shows_unset_sentinel遗留记录在 GET 中显示unset哨兵。八、实践建议如何正确操作 Dashboard 用户 API基于本次修复的语义以下操作模式值得在实际开发中遵循1. 仅编辑备注不涉及权限时最稳妥的方式是省略scopes字段意图keep或回传unset哨兵。若使用读-改-写模式回传 GET 的完整对象则必须保证scopes与角色默认集一致无序集合相等否则会被当作显式列表处理。2. 查询用户实际权限时使用GET /current_user返回effective_scopes_response始终为具体列表而不是GET /users/:username返回存储态可能是unset哨兵。GET /user_scopes可获取完整的静态 scope 目录。3. 为普通用户赋权时显式列表会被原样存储使用unset可把用户恢复到角色默认的隐式继承状态。注意非管理员角色不能持有user_management、mfa_management、sso_management、api_key_management这 4 个登录专用 scopeemqx_dashboard_api.erl 的validate_role_scope_compat/2校验全局管理员的显式列表也不能混用特权 scope 与受限 scopemaybe_check_privilege_mutex/2。4. 升级集群升级到包含本修复的版本后默认管理员的固化 scope 会在启动时被自动清除无需手工干预升级前若曾通过 API 给默认管理员写入过显式列表建议升级后通过GET /users/:username确认其scopes已恢复为unset。九、总结fix-18009 变更解决的是一个隐蔽而典型的 API 设计问题当读-改-写模式与隐式默认权限语义相遇时往返的数据形态必须被写入端正确理解。EMQX 通过引入keep/unset/{set, L}三态写入意图、无序集合等价比较、unset哨兵以及启动自愈清理四层机制使仅编辑默认管理员备注这一高频操作恢复正常同时保证了角色默认权限的前向兼容继承。对于任何深度集成 Dashboard 用户 API 的自动化平台而言理解这套 scope 语义是避免权限误写、账号误锁的必备知识。赞分享后端物联网消息队列通信【免费下载链接】emqxThe most scalable and reliable MQTT broker for AI, IoT, IIoT and connected vehicles项目地址https://gitcode.com/gh_mirrors/em/emqx点击查看免费下载相关推荐zCore容器化开发Docker环境搭建与持续集成完整教程zCore容器化开发Docker环境搭建与持续集成完整教程 zCore是一个采用Rust语言重新实现的Zircon微内核项目通过Docker容器化开发可以显后端物联网消息队列通信Label Studio 乳腺癌钼靶分类标注模板基于 BI-RADS 的四视图网格标注方案Label Studio 乳腺癌钼靶分类标注模板基于 BI RADS 的四视图网格标注方案 本文以 Label Studio 社区贡献模板 breast_ca后端物联网消息队列通信EMQX Dashboard 用户账户管理 API 收紧 API Key 权限fix-17040 安全修复深度解析EMQX Dashboard 用户账户管理 API 收紧 API Key 权限fix 17040 安全修复深度解析 本篇技术指南围绕 EMQX 仓库变更记录后端物联网消息队列通信上一篇CyberChef离线版完整指南加密、解码、取证分析一步到位下一篇如何用AI把英文PDF论文翻成中文公式和排版还一个不错PDFMathTranslate 5分钟上手指南创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表