嵌套组权限计算需分层绑定:用户属全局组,全局组加入域本地组,权限仅赋域本地组;成员查询须递归展开,ldap用matching_rule_in_chain,sql用with recursive cte,限制深度防环路。
嵌套组的权限计算与成员查询不是“自动继承”的直觉操作,而是依赖明确的模型设计、目录服务支持和查询逻辑配合。关键不在“能不能嵌套”,而在“怎么让嵌套有意义且可审计”。
权限计算:必须解耦身份、角色与资源三要素
直接给用户加权限或让组包含组再赋权,会导致权限漂移、无法回溯。正确路径是分层绑定:
- 用户只属于全局组(Global Group),例如 G_Marketing_Staff、G_IT_Ops,体现“他是谁、属于哪个部门/职能”
- 全局组只被加入域本地组(Domain Local Group),例如 DL_CRM_DB_Read、DL_SalesDocs_Edit,体现“能对什么资源执行什么动作”
- 权限只赋予域本地组,且仅在文件系统(NTFS)、共享、数据库或应用策略层面设置——不许绕过这层直接授给全局组或用户
这样,一个用户的最终权限 = 所有全局组 → 所有被包含的域本地组 → 所有被授予的权限 的并集。系统不做“叠加优先级”判断,只做布尔合并(允许即生效,无拒绝覆盖逻辑)。
成员查询:递归遍历是基础,但需控制深度与来源
查“用户A属于哪些组”,不能只读 directGroups 属性,必须递归展开嵌套关系:
- LDAP/AD 环境中,用 LDAP_MATCHING_RULE_IN_CHAIN(如
memberOf:1.2.840.113556.1.4.1941:)可单次查询所有祖先组,无需手动循环 - Cloudreve、Spring Security 等支持 DFS 递归的系统,会调用类似
getNestedGroups(groupDN)的函数逐层下探,但建议限制最大深度为5,防环路或超时 - MySQL 或 PostgreSQL 中查角色继承链,必须用 WITH RECURSIVE CTE,且第一段非递归查询要锚定起点(如用户直连角色),否则结果不可控
常见陷阱与规避方式
很多权限异常其实源于嵌套配置失当:
- 跨域嵌套失效:全局组不能跨域加成员(除非林功能级别 ≥ 2003),但可被其他域的域本地组包含——确认信任关系和功能级别再规划
- MySQL 角色嵌套不自动激活:GRANT 'role_a' TO 'role_b' 成功,但用户拥有 role_b 后,不会自动获得 role_a 权限,必须 SET ROLE 'role_b', 'role_a' 或设 DEFAULT ROLE 包含两者
- SQL 子查询返回多行报错:WHERE role = (SELECT …) 必炸;改用 WHERE role IN (SELECT …) 或 EXISTS 结构,并注意 NULL 值导致整行过滤











