AUTHID DEFINER模式下角色权限默认不生效,仅认可定义者被直接授予的系统及对象权限;编译和执行时均忽略DBA等角色权限,必须显式GRANT如CREATE ANY TABLE或SELECT ON hr.employees给定义者用户。

定义者权限(AUTHID DEFINER)下角色权限默认不生效
Oracle 在编译和执行 AUTHID DEFINER 存储过程时,会以**定义者(即过程属主)的身份做静态权限检查**,但只认可该用户**直接授予的系统权限和对象权限**,完全忽略通过角色获得的权限。哪怕 DBA_ROLE_PRIVS 显示你已被授予 DBA 角色,只要没显式执行 GRANT CREATE TABLE TO owner_user,过程里写 EXECUTE IMMEDIATE 'CREATE TABLE t1' 就会报 ORA-01031。
SESSION_ROLES 为空 ≠ 没授权,而是 DEFINER 模式根本不看它
运行 SELECT * FROM SESSION_ROLES 返回空行,只说明当前会话未启用角色——但这对 AUTHID DEFINER 过程毫无影响,因为该模式压根不读这个视图。它只查 SESSION_PRIVS(仅含直授系统权限)和对象级授权记录(如 DBA_TAB_PRIVS 中 GRANTEE = 'OWNER_USER' 的条目)。常见误判是:看到 SESSION_ROLES 为空,就去 SET ROLE ALL,结果过程照样失败——因为问题不在“会话是否启用角色”,而在“定义者是否被直授权限”。
动态 SQL 不绕过权限校验,反而放大 DEFINER 模式的限制
用 EXECUTE IMMEDIATE 执行 DDL 或跨 schema 查询,并不会跳过权限检查;相反,它把校验时机从编译期推迟到运行期,但校验主体仍是定义者,且仍不认角色。例如过程里写 EXECUTE IMMEDIATE 'SELECT * FROM hr.employees',必须确保定义者用户已直获 GRANT SELECT ON hr.employees TO owner_user,而不能依赖 SELECT_CATALOG_ROLE 或 RESOURCE 角色。
-
CREATE ANY TABLE、SELECT ANY DICTIONARY等系统权限也必须直授,不能靠角色间接拥有 - 同义词或视图不改变权限归属——权限检查最终穿透到基表,且基表权限也得直授给定义者
- 若过程调用另一个用户下的包,而该包内部访问了第三用户的表,则定义者还需对那个第三用户的表直授权限
为什么 AUTHID CURRENT_USER 不是万能解法
改成 AUTHID CURRENT_USER 后,权限检查转向调用者,此时角色权限生效(SESSION_ROLES 非空即可),但引入新约束:
- 调用者必须在连接后手动执行
SET ROLE ALL(JDBC/cx_Oracle 默认不自动启用角色) - 所有被访问的对象(表、序列、函数等)权限都需落在调用者名下,而非定义者
- 无法再复用定义者统一管理的权限模型,多租户或统一运维场景下维护成本陡增
真正卡住人的地方,往往不是不知道该授什么权,而是没意识到 Oracle 在 DEFINER 模式下对角色权限做了硬性屏蔽——它不是 bug,是设计如此。每次遇到 ORA-01031,第一反应不该是加角色,而是打开 SESSION_PRIVS 和 DBA_TAB_PRIVS,确认定义者是否真有那条直授权限。


















