正如大家所知,Oracle从8i开始引入了调用者权限体系结构,之前一直使用定义者权限体系结构。
一、简单介绍一下二者的使用方法
oracle创建存储过程时,若不指定authid参数,则调用权限验证默认是definer,也就是存储过程执行时,以这个存储过程的创建者的身份来验 证存取权限;可以在创建存储过程时指定authid为current_user,从而在执行存储过程时根据当前调用存储过程的用户权限来验证。
举个例子说明:
比如有两个用户test和user1,test用户下有个表user1table,用户user1只有这个表的select权限。test创建了一个存储 过程testproc,使用默认的authid调用方式,存储过程内容为“insert into user1table ....”,然后使用grant execute on testproc to user1将执行权限赋予user1,那么user1就可以调用这个存储过程向user1table添加数据。注意:此时user1并没有对表 user1table的insert权限,但由于testproc执行的时候,是根据test用户的权限来验证的,因此insert语句不会出现权限不足 的提示。
假如创建testproc是添加了authid current_user,则当user1调用test.testproc存储过程时,就会报两个错误:一是user1table未定义,二是对 user1table没有insert权限。对于第一个问题,原因是user1table仅在test用户模式下,user1用户不能直接引用,可以在定 义testproc时使用test.user1table方式;对于第二个问题,由于user1没有对user1table的insert权限,因此无法 执行这个存储过程,除非给user1用户增加user1table表的insert权限。
二、定义者权限与调用者权限之间差异
关于定义者权限与调用者权限之间的相通点或者是各自优势本文不做探讨,这里仅描述调用者权限与定义者权限之间的差异,在我看来,主要有三个方面:
1、执行的schema不同,操作的对象也不同
l 在定义者(definer)权限下,执行的用户操作的schema为定义者,所操作的对象是定义者在编译时指定的对象。
l 在调用者(invoker)权限下,执行的用户操作的schema为当前用户,所操作的对象是当前模式下的对象。
例如:
E:\ora10g>sqlplus "/ as sysdba"
连接到:
Oracle Database 10g Enterprise Edition Release 10.2.0.3.0 - Production
With the Partitioning, OLAP and Data Mining options
SQL>create user tmpa identified by tmpa;
用户已创建。
SQL>grant connect,resource to tmpa;
授权成功。
SQL>create user tmpb identified by tmpb;
用户已创建。
SQL>grant connect,resource to tmpb;
授权成功。
SQL>conn tmpa/tmpa
已连接。
SQL>set sqlprompt TMPA>
TMPA>create table tmptbl(str varchar2(50));
表已创建。
TMPA>insert into tmptbl values ('I''m ownered by user:tmpa');
已创建 1 行。
TMPA>commit;
提交完成。
TMPA>create or replace procedure definer_proc as
2 begin
3 for x in (select sys_context('userenv', 'current_user') current_user,
4 sys_context('userenv', 'session_user') session_user,
5 sys_context('userenv', 'current_schema') current_schema,
6 str
7 from tmptbl) loop
8 dbms_output.put_line('Current User: ' || x.current_user);
9 dbms_output.put_line('Session User: ' || x.session_user);
10 dbms_output.put_line('Current Schema: ' || x.current_schema);
11 dbms_output.put_line('Tables Value: ' || x.str);
12 end loop;
13 end;
14 /
过程已创建。
TMPA>create or replace procedure invoker_proc AUTHID CURRENT_USER as
2 begin
3 for x in (select sys_context('userenv', 'current_user') current_user,
4 sys_context('userenv', 'session_user') session_user,
5 sys_context('userenv', 'current_schema') current_schema,
6 str
7 from tmptbl) loop
8 dbms_output.put_line('Current User: ' || x.current_user);
9 dbms_output.put_line('Session User: ' || x.session_user);
10 dbms_output.put_line('Current Schema: ' || x.current_schema);
11 dbms_output.put_line('Tables Value: ' || x.str);
12 end loop;
13 end;
14 /
过程已创建。
TMPA>set serveroutput on
TMPA>grant execute on definer_proc to tmpb;
授权成功。
TMPA>grant execute on invoker_proc to tmpb;
授权成功。
TMPA>exec definer_proc;
Current User: TMPA
Session User: TMPA
Current Schema: TMPA
Tables Value: I'm ownered by user:tmpa
PL/SQL 过程已成功完成。
TMPA>exec invoker_proc;
Current User: TMPA
Session User: TMPA
Current Schema: TMPA
Tables Value: I'm ownered by user:tmpa
PL/SQL 过程已成功完成。
可以看到,对于owner所拥有的对象,当前用户和session用户都是当前执行过程的用户;
新开一个连接,以tmpb用户登陆再执行看看:
E:\ora10g>sqlplus tmpb/tmpb
连接到:
Oracle Database 10g Enterprise Edition Release 10.2.0.3.0 - Production
With the Partitioning, OLAP and Data Mining options
SQL> set sqlprompt TMPB>
TMPB>create table tmptbl(str varchar2(50));
表已创建。
TMPB>insert into tmptbl values ('I''m ownered by user:tmpb');
已创建 1 行。
TMPB>commit;
提交完成。
TMPB>set serveroutput on
TMPB>exec tmpa.definer_proc;
Current User: TMPA
Session User: TMPB
Current Schema: TMPA
Tables Value: I'm ownered by user:tmpa
PL/SQL 过程已成功完成。
TMPB>exec tmpa.invoker_proc;
Current User: TMPB
Session User: TMPB
Current Schema: TMPB
Tables Value: I'm ownered by user:tmpb
PL/SQL 过程已成功完成。
调用非owner的过程,对于定义者权限的过程,虽然session是tmpb,但当前用户仍然是tmpa,访问的对象也是tmpa的表,而对于调用者权限的过程,当前session和用户都是当前执行过程的用户tmpb,而且访问的对象也是当前用户的对象。
2、执行的权限不同
l 在定义者(definer)权限下,当前用户的权限为角色无效情况下所拥有的权限。
l 在调用者(invoker)权限下,当前用户的权限为当前所拥有的权限(含角色)。
例如:
仍用前文中的用户
TMPA>create or replace procedure createtbl_definer as
2 begin
3 execute immediate 'create table tmptbl2 (id number)';
4 end;
5 /
过程已创建。
TMPA>create or replace procedure createtbl_invoker AUTHID CURRENT_USER as
2 begin
3 execute immediate 'create table tmptbl2 (id number)';
4 end;
5 /
过程已创建。
首先执行定义者权限过程:
TMPA>exec createtbl_definer;
BEGIN createtbl_definer; END;
*
第 1 行出现错误:
ORA-01031: 权限不足
ORA-06512: 在 "TMPA.CREATETBL_DEFINER", line 3
ORA-06512: 在 line 1
由于角色无效,相当于当前用户没有了建表权限,因此创建失败,这也正是为什么过程中执行DDL语句需要显示授权的原因。
TMPA>exec createtbl_invoker;
PL/SQL 过程已成功完成。
TMPA>desc tmptbl2
名称 是否为空? 类型
----------------------------------------- -------- ----------------------------
ID NUMBER
执行调用者权限过程,能够成功创建!
3、执行的效率不同
l 在定义者(definer)权限下,过程被静态编译静态执行(相对而言),所执行sql语句在共享区池中是可被共享使用的
l 在调用者(invoker)权限下,过程静态编译,但动态执行,虽然执行的语句相同,但不同用户执行,其sql语句在共享池中并不能共享。
归根结底,正如tom所说,调用者权限体系结构的确拥有非常强大的功能,但只有当你使用得当时才能感受到其优势。