因为role_role_privs仅记录角色间授予关系(如r1→r2),不关联用户;查用户完整角色链需联合dba_role_privs与role_role_privs,用start with...connect by递归查询,并注意grantee/granted_role语义对齐及default_role状态。
为什么只查 role_role_privs 查不出用户实际拥有的嵌套角色
因为 role_role_privs 只存角色之间的授予关系(比如 r1 → r2),完全不涉及用户。它像一张“角色关系图”,但没有起点——你不知道哪个用户站在图的哪个入口。常见错误是:看到 select * from role_role_privs where role = 'r1' 返回了 r2,就以为用户自动有了 r2;其实前提是该用户必须先被直接授予了 r1,否则这条链根本走不通。
怎么从用户出发查完整角色链(Oracle 11g 兼容写法)
Oracle 11g 不支持 WITH RECURSIVE,必须用 START WITH ... CONNECT BY。关键不是查 ROLE_ROLE_PRIVS 本身,而是把它和 DBA_ROLE_PRIVS 联合起来构建递归路径:
-
START WITH从用户开始:找所有grantee = 'USER_A'的直接角色 -
CONNECT BY PRIOR granted_role = grantee表示“上一层授出的角色,是下一层的被授方”,这样才能顺着R1 → R2 → R3往下钻 - 必须加
DISTINCT,否则多条路径(如R1→R3和R2→R3)会让R3重复出现 - 漏掉
NOCYCLE在测试环境容易触发ORA-01436: CONNECT BY loop in user data,尤其当存在R1→R2→R1这类循环授权时
实操语句:
SELECT DISTINCT granted_role FROM ( SELECT grantee, granted_role FROM DBA_ROLE_PRIVS UNION ALL SELECT role AS grantee, granted_role FROM ROLE_ROLE_PRIVS ) START WITH grantee = 'USER_A' CONNECT BY NOCYCLE PRIOR granted_role = grantee;
ROLE_ROLE_PRIVS 和 DBA_ROLE_PRIVS 字段含义别搞反
两张表的 grantee 和 granted_role 方向一致,但语义不同:
- 在
DBA_ROLE_PRIVS中:grantee是用户或角色名,granted_role是被授予的角色名(即用户 A 被授了角色 R) - 在
ROLE_ROLE_PRIVS中:grantee是角色名,granted_role是被授出的角色名(即角色 R1 被授了角色 R2) - 所以合并查询时,要把
ROLE_ROLE_PRIVS.role当作grantee,才能对齐递归逻辑
误把 ROLE_ROLE_PRIVS.granted_role 当起点,会导致递归方向全错,查出来的是“谁有这个角色”,而不是“这个用户能走到哪些角色”。
查到角色后,怎么确认它到底含哪些权限
查出用户可达的所有角色只是第一步。每个角色还可能包含系统权限(查 DBA_SYS_PRIVS)和对象权限(查 DBA_TAB_PRIVS)。注意:
-
DBA_SYS_PRIVS.grantee字段填的是角色名,不是用户名;所以得用上一步查出的角色列表做IN或JOIN - 不要用
ROLE_SYS_PRIVS替代DBA_SYS_PRIVS—— 前者只对当前会话生效,且不含管理员显式授予的权限 - 如果角色被授予了
WITH ADMIN OPTION,它还能再授给别人,但这不影响当前用户的权限集合,只是管理能力
最易忽略的一点:角色是否为 DEFAULT_ROLE。即使查到了某个角色,如果它在 DBA_ROLE_PRIVS 里 DEFAULT_ROLE = 'NO',且用户没在会话中显式 SET ROLE,那这个角色的权限在当前连接里实际是不可用的。











