查角色a是否包含角色b需用role_role_privs视图,其中grantee为父角色、granted_role为子角色,注意大小写及dba权限;递归查继承链须用start with grantee='a' connect by prior granted_role=grantee,并警惕自授循环。

查角色 A 是否包含角色 B(直接嵌套)
最常用也最容易出错的场景:你想确认 DBA 角色是否直接包含了 SELECT_CATALOG_ROLE。这时候不能查 ROLE_SYS_PRIVS(它只存系统权限),得盯住 ROLE_ROLE_PRIVS 视图:
-
GRANTEE是“被授角色者”,即父角色(比如DBA) -
GRANTED_ROLE是“被授予的角色”,即子角色(比如SELECT_CATALOG_ROLE) - 执行:
SELECT GRANTED_ROLE FROM ROLE_ROLE_PRIVS WHERE GRANTEE = 'DBA';
注意大小写:Oracle 默认大写存储角色名,'dba' 会查不到结果。另外普通用户无权查 ROLE_ROLE_PRIVS,需 DBA 权限或换用 USER_ROLE_PRIVS(但后者只返回当前用户直接受授的角色,不反映角色间关系)。
递归查完整继承链(A → B → C → D)
单层查询只能看到直接父子关系,而真实环境里常有三层甚至更深的嵌套(如 APP_ADMIN → APP_USER → CONNECT)。必须用 CONNECT BY 递归查询:
- 起始点用
START WITH GRANTEE = 'APP_ADMIN',不是GRANTED_ROLE - 递推条件是
CONNECT BY PRIOR GRANTED_ROLE = GRANTEE(上一层的子角色,是下一层的父角色) - 加
LEVEL字段能看清嵌套深度,避免误判间接授权路径 - 示例语句:
SELECT LEVEL, GRANTEE, GRANTED_ROLE FROM ROLE_ROLE_PRIVS START WITH GRANTEE = 'APP_ADMIN' CONNECT BY PRIOR GRANTED_ROLE = GRANTEE;
常见坑:如果存在角色自授(比如 APP_ADMIN 授予了自己),Oracle 会报 ORA-01436: CONNECT BY loop。生产环境务必先人工确认无循环引用,或加 NOCYCLE(但 Oracle 12c+ 才支持,旧版本不行)。
为什么 SESSION_ROLES 不显示嵌套来源?
你执行 SELECT * FROM SESSION_ROLES; 看到一堆角色,但无法判断哪个是直接授予、哪个是嵌套继承来的——这是设计使然。SESSION_ROLES 只回答“此刻哪些角色已生效”,不记录路径。
- 它包含:默认激活的角色、手动
SET ROLE激活的角色、以及所有被这些角色间接包含的子角色 - 但它不存
GRANTEE/GRANTED_ROLE关系,也没LEVEL字段 - 想定位问题(比如某权限突然失效),必须回溯到
ROLE_ROLE_PRIVS+ 当前用户的USER_ROLE_PRIVS交叉比对
典型误操作:看到 SELECT_CATALOG_ROLE 在 SESSION_ROLES 里,就以为它被直接授予了用户——其实它可能只是通过 DBA 间接继承的,删掉 DBA 角色,它立刻消失。
查角色定义时容易忽略 ADMIN_OPTION
角色嵌套不是单纯“包含”,还受 ADMIN_OPTION 控制。这个字段决定子角色能否被进一步转授:
- 查嵌套关系时,建议同时查
ADMIN_OPTION:SELECT GRANTEE, GRANTED_ROLE, ADMIN_OPTION FROM ROLE_ROLE_PRIVS WHERE GRANTEE = 'APP_ADMIN'; -
ADMIN_OPTION = 'YES'表示该嵌套可传递;'NO'表示子角色仅对该父角色有效,不能由父角色持有者再授予他人 - 很多权限失控事故,根源就是误设了
ADMIN_OPTION = YES,导致角色链意外扩散
真正要理清一个角色的全部能力,不能只看“它含谁”,还得看“它能不能把含的东西再给别人”——这点在审计和权限回收时特别关键,但常被跳过。











