DBA_ROLE_PRIVS 不显示嵌套角色权限,因其仅存储直接授予关系,不递归展开;需用 CONNECT BY 或 WITH RECURSIVE 从用户出发递归查询可达角色链。
查 DBA_ROLE_PRIVS 时为什么看不到嵌套角色的权限?
因为 dba_role_privs 只存直接授予的关系,不递归展开。比如用户 a 被授了角色 r1,r1 又被授了 r2,那么 dba_role_privs 里只有 a→r1 和 r1→r2 两条记录,不会自动告诉你 a 间接拥有 r2 的权限。
常见错误现象:SELECT * FROM DBA_ROLE_PRIVS WHERE grantee = 'USER_A' 返回空,但用户实际能执行某些需角色权限的操作——说明权限来自嵌套角色,而非直授。
- 必须用递归查询(
CONNECT BY或WITH RECURSIVE)向上追溯所有可到达的角色 - 注意
ROLE列是被授方,GRANTEE是授予方;嵌套分析要从用户出发,找它能“走到”的所有角色 - Oracle 12c+ 支持
WITH RECURSIVE,但老版本只能靠START WITH ... CONNECT BY
Oracle 递归查用户完整角色链:用 CONNECT BY 实操
这是最稳定、兼容性最好的方式,适用于 Oracle 9i 及以上版本。
示例:查用户 'SCOTT' 所有可达角色(含嵌套):
SELECT DISTINCT granted_role FROM DBA_ROLE_PRIVS START WITH grantee = 'SCOTT' CONNECT BY PRIOR granted_role = grantee;
关键点:
-
START WITH grantee = 'SCOTT'表示起点是用户本身 -
CONNECT BY PRIOR granted_role = grantee意思是:上一层的granted_role,是下一层的grantee—— 这才构成角色继承链 - 漏掉
DISTINCT容易因多路径重复返回同一角色(比如 R1→R3、R2→R3,用户同时有 R1 和 R2) - 该语句不包含“谁授的”“何时授的”,如需审计信息,得额外关联
DBA_AUDIT_TRAIL或DBA_TAB_PRIVS
为什么不能只查 ROLE_ROLE_PRIVS?
ROLE_ROLE_PRIVS 确实存角色之间的授予关系(R1 → R2),但它完全不涉及用户,也没办法反向定位到某个具体用户最终能拿到哪些角色。
常见误用:
- 只查
SELECT * FROM ROLE_ROLE_PRIVS WHERE role = 'R1',以为这就代表用户有了 R2 —— 错,前提是用户真被授了 R1 - 把
DBA_ROLE_PRIVS和ROLE_ROLE_PRIVS当成两张独立表去JOIN,没建递归逻辑,结果要么漏层、要么死循环(比如 R1→R2→R1) - 没加
NOCYCLE导致递归报错ORA-01436: CONNECT BY loop in user data,尤其在测试环境角色循环授权时很常见
想看某角色具体有哪些系统权限?别跳过 ROLE_SYS_PRIVS
查完角色链只是第一步,真正影响操作的是这些角色背后的系统权限(比如 CREATE TABLE、ALTER SYSTEM)。
典型组合用法:
SELECT r.granted_role, s.privilege FROM ( SELECT DISTINCT granted_role FROM DBA_ROLE_PRIVS START WITH grantee = 'SCOTT' CONNECT BY PRIOR granted_role = grantee ) r JOIN ROLE_SYS_PRIVS s ON r.granted_role = s.role;
注意:
-
ROLE_SYS_PRIVS不区分大小写,但角色名默认大写,granted_role来自DBA_ROLE_PRIVS也是大写,直接等值 JOIN 安全 - 如果要查对象权限(如对某张表的
SELECT),得换用ROLE_TAB_PRIVS,不是ROLE_SYS_PRIVS - 某些权限(如
UNLIMITED TABLESPACE)在ROLE_SYS_PRIVS里不显式列出,而是由表空间配额隐式控制,得额外查DBA_TS_QUOTAS
嵌套深度本身没有硬限制,但超过 5 层就容易出性能问题或管理混乱;真正难的不是写 SQL,而是确认哪些角色该启用、哪些该回收——权限模型一旦跑起来,没人记得清最初是谁在哪条链上加了一笔。










