查HR用户全部系统权限须用DBA_*视图并具备SELECT_CATALOG_ROLE或DBA权限;因Oracle无开箱即用汇总视图,需手动合并直接授权与角色继承权限(含两层角色嵌套),且用户名必须大写。

直接查某个用户(比如 HR)的全部系统权限,必须用 DBA_* 视图,且当前登录用户得有 SELECT_CATALOG_ROLE 或 DBA 权限;否则只能查自己(USER_* 视图),看不到别人。
查指定用户的全部系统权限(含角色继承)
Oracle 不提供开箱即用的“一键汇总”视图,必须手动合并直接授予的权限 + 所有角色携带的权限。关键点是:角色可能嵌套(A 角色包含 B 角色,B 又含 C),但 ROLE_SYS_PRIVS 只展一层,所以不能只查一次子查询。
推荐用递归方式(Oracle 11g+ 支持)或分层查询,但最稳妥、兼容性最好的写法是两层展开(覆盖常见嵌套):
SELECT DISTINCT privilege FROM ( -- 直接授予该用户的系统权限 SELECT privilege FROM dba_sys_privs WHERE grantee = 'HR' UNION ALL -- 该用户拥有的角色 → 角色的系统权限 SELECT rp.privilege FROM dba_role_privs rp1 JOIN role_sys_privs rp ON rp1.granted_role = rp.role WHERE rp1.grantee = 'HR' UNION ALL -- 该用户拥有的角色 → 角色拥有的角色 → 这些子角色的系统权限(第二层) SELECT rp2.privilege FROM dba_role_privs rp1 JOIN dba_role_privs rp2 ON rp1.granted_role = rp2.grantee JOIN role_sys_privs rp3 ON rp2.granted_role = rp3.role WHERE rp1.grantee = 'HR' ) ORDER BY privilege;
-
HR必须大写 —— Oracle 默认用户名/角色名存为大写,小写会查不到 - 如果用户被授予了自定义角色(如
APP_DEVELOPER),而该角色又包含另一个角色(如READER_ROLE),第二层 UNION 就能捕获到READER_ROLE的权限 - 三层及以上嵌套极少见,真有可改用
WITH递归查询,但多数生产环境两层已够用
查指定用户对具体对象的全部对象权限(含角色继承)
对象权限(如 SELECT 某张表)不支持跨角色自动展开到 DBA_TAB_PRIVS,必须手动关联角色链。难点在于:ROLE_TAB_PRIVS 只存角色→对象权限,不存角色→角色关系。
以下语句查 HR 对所有表/视图的 SELECT 权限(含直接授予 + 所有角色授予):
SELECT owner, table_name, privilege, grantable, 'direct' AS source FROM dba_tab_privs WHERE grantee = 'HR' AND privilege = 'SELECT' UNION ALL SELECT rtp.owner, rtp.table_name, rtp.privilege, rtp.grantable, 'via ' || rp.granted_role FROM dba_role_privs rp JOIN role_tab_privs rtp ON rp.granted_role = rtp.role WHERE rp.grantee = 'HR' AND rtp.privilege = 'SELECT' ORDER BY owner, table_name;
- 注意区分
DBA_TAB_PRIVS(用户直授)和ROLE_TAB_PRIVS(角色所带)—— 后者不带grantee字段,必须通过DBA_ROLE_PRIVS关联 -
grantable为YES表示该权限可再转授,但仅对直接授予有效;角色继承来的权限,即使原角色有ADMIN_OPTION,也不会体现在这里 - 若要查其他权限(如
UPDATE或EXECUTE),改privilege = 'SELECT'即可
为什么不用 SESSION_PRIVS?
SESSION_PRIVS 看起来最省事,但它只反映「当前会话实际生效的权限」,受三重限制:
- 只返回已启用的默认角色中的权限(
DEFAULT_ROLE = 'YES') - 不包含被
ALTER USER ... DEFAULT ROLE NONE显式禁用的角色权限 - 查不了别人 —— 它是
USER_*级视图,永远只返回当前登录用户自己的会话权限
所以 SELECT * FROM session_privs 对诊断“某用户理论上有没有权限”毫无帮助,它只告诉你“此刻这个连接能干啥”。
容易忽略的权限来源:WITH GRANT OPTION 和 OS_ROLES
除了角色继承,还有两个隐蔽路径:
- 如果
HR曾被GRANT SELECT ON emp TO scott WITH GRANT OPTION,那么scott再授出去的权限,HR并不自动拥有 —— Oracle 权限不级联,这点和系统权限的WITH ADMIN OPTION不同 - 若数据库启用了操作系统认证(
os_authent_prefix),用户可能通过 OS 组获得权限,这类权限不会出现在任何DBA_*视图里,得查V$PWFILE_USERS和操作系统组配置
真正要确认一个用户“能不能执行某操作”,不能只看权限列表,还得结合其默认角色、当前会话设置、以及目标对象的实际属主和权限链 —— 权限查全只是第一步。











