Oracle中定义者权限和调用者权限的示例分析

这篇文章给大家分享的是有关Oracle中定义者权限和调用者权限的示例分析的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。

成都创新互联-专业网站定制、快速模板网站建设、高性价比玉溪网站开发、企业建站全套包干低至880元,成熟完善的模板库,直接使用。一站式玉溪网站制作公司更省心,省钱,快速模板网站建设找我们,业务覆盖玉溪地区。费用合理售后完善,十多年实体公司更值得信赖。

定义者权限:定义者权限指使用它所有者的权限,而不是当前用户来执行过程。因此,你可以限制用户执行的数据库操作,允许他们仅通过运行定义者权限的过程和函数访问数据。创建过程、函数和程序包的默认权限是定义者权限。

 

调用者权限:在当前的用户模式下用当前的用户权限来执行过程。换句话说,就是调用者的权限过程并不与某个特定的用户或模式绑定。调用者权限程序可以使应用程序开发人员很容易的将应用逻辑集中起来,即使底层的数据在用户和模式中被划分。创建时需要显式使用AUTHID CURRENT_USER来定义调用者过程。

(注意:在阅读下面案例的时候注意sqlplus的使用的不同用户)

具体演示如下所示:

1、创建两个测试用户wjq1和wjq2,并分别授权

SYS@seiang11g>create user wjq1 identified by wjq1 default tablespace seiang;

User created.

SYS@seiang11g>create user wjq2 identified by wjq2 default tablespace seiang;

User created.

SYS@seiang11g>grant connect,resource to wjq1,wjq2;

Grant succeeded.

2、切换到用户wjq1,创建两个过程proc_definer和proc_invoker

过程1:定义者权限,为创建过程的默认权限

WJQ1@seiang11g>create or replace procedure proc_definer is

  2  begin

  3     dbms_output.put_line('Current User:'|| sys_context('userenv','current_user'));

  4     dbms_output.put_line('Session User:'|| sys_context('userenv','session_user'));

  5     dbms_output.put_line('Current Schema:'|| sys_context('userenv','current_schema'));

  6  end proc_definer;

  7  /

Procedure created.

过程2:使用使用者权限

WJQ1@seiang11g>create or replace procedure proc_invoker authid current_user is

  2  begin

  3     dbms_output.put_line('Current User:'|| sys_context('userenv','current_user'));

  4     dbms_output.put_line('Session User:'|| sys_context('userenv','session_user'));

  5     dbms_output.put_line('Current Schema:'|| sys_context('userenv','current_schema'));

  6  end proc_invoker;

  7  /

Procedure created.

3、查看两个过程的权限

WJQ1@seiang11g>select object_name,procedure_name,authid from user_procedures

  2  where object_name like '%PROC%';

OBJECT_NAME                    PROCEDURE_NAME                 AUTHID

------------------------------ ------------------------------ ------------

PROC_INVOKER                                                  CURRENT_USER

PROC_DEFINER                                                  DEFINER

4、在用户wjq1下分别执行定义者权限和使用者权限的过程

WJQ1@seiang11g>set serveroutput on

WJQ1@seiang11g>

WJQ1@seiang11g>exec proc_definer;

Current User:WJQ1

Session User:WJQ1

Current Schema:WJQ1

PL/SQL procedure successfully completed.

WJQ1@seiang11g>exec proc_invoker;

Current User:WJQ1

Session User:WJQ1

Current Schema:WJQ1

PL/SQL procedure successfully completed.

5、将用户wjq1创建的两个过程授权给用户wjq2

WJQ1@seiang11g>grant execute on proc_definer to wjq2;

Grant succeeded.

WJQ1@seiang11g>grant execute on proc_invoker to wjq2;

Grant succeeded.

6、在用户wjq2下分别调用两个过程,结果显示在调用者权限下,程序在当前用户下用当前用户的权限执行

WJQ2@seiang11g>set serveroutput on

WJQ2@seiang11g>exec wjq1.proc_definer;

Current User:WJQ1

Session User:WJQ2

Current Schema:WJQ1

PL/SQL procedure successfully completed.

WJQ2@seiang11g>exec wjq1.proc_invoker;

Current User:WJQ2

Session User:WJQ2

Current Schema:WJQ2

PL/SQL procedure successfully completed.

通过上面的简单的演示,已经对定义者权限和调用者权限有了一定的认识和理解,但是仅仅初步的了解在生产环境中,遇到实际的案例还是有点摸不着头脑,下面通过两个实际的案例来分析定义者权限和调用者权限,更加深入的去理解它们的使用方法。

在存储过程中,时常会遇到这样一种场景:用户A下有一个存储过程(或者函数体、包体)Proc,在过程中间引用了对象obj。在编译存储过程时,是要求用户A有对象obj的权限的,如果没有,则系统报编译错误。当成功进行编译之后,用户A将执行execute存储过程Proc的权限赋给了用户B。但是用户B不一定拥有对象obj的使用权限,那么问题就来了,此时用户B能否成功执行存储过程Proc呢?

下面我们通过实验来进行验证:

接着上面例子,用户wjq1和wjq2除了拥有connect和resource角色的权限之外,出于实验的目的,我们将select any dictionary的系统权限赋予给用户wjq1

SYS@seiang11g>grant select any dictionary to wjq1;

Grant succeeded.

select any dictionary的系统权限意味着用户可以访问数据字典视图层面的视图中的对象数据。

WJQ1@seiang11g>select count(*) from dba_objects;

  COUNT(*)

----------

     86993

WJQ1@seiang11g>create or replace procedure proc_wjq1 is

  2  i number;

  3  begin

  4     select count(*) into i from dba_objects;

  5     dbms_output.put_line(to_char(i));

  6  end;

  7  /

Procedure created.

WJQ1@seiang11g>set serveroutput on

WJQ1@seiang11g>

WJQ1@seiang11g>exec proc_wjq1;

86994

PL/SQL procedure successfully completed. 

由上可见:授予select any dictionary的用户wjq1可以对dba_objects视图进行访问操作。同时,存储过程proc_wjq1也可以执行编译操作。

案例一:定义者权限

紧接着上面的实验,对于wjq2用户,只有执行wjq1用户下proc_wjq1存储过程权限,但是没有访问dba_objects视图权限,看实际效果。

用户wjq2只具有基本的connect和resource权限。将proc_wjq1过程的执行权限授权给wjq2

WJQ1@seiang11g>grant execute on proc_wjq1 to wjq2;

Grant succeeded. 

之后,检查wjq2用户下,过程proc_wjq1的执行情况

WJQ2@seiang11g>select count(*) from dba_objects;

select count(*) from dba_objects

                     *

ERROR at line 1:

ORA-00942: table or view does not exist

wjq2用户没有dba_objects权限,显示访问必然报错

WJQ2@seiang11g>exec wjq1.proc_wjq1;

86994

PL/SQL procedure successfully completed.

结果显而易见,wjq2虽然没有访问dba_objects权限,但是因为拥有执行proc_wjq1的权限,在执行proc_wjq1的时候,也是可以在方法中访问到dba_objects。显然,此时wjq2在执行proc_wjq1上应用了wjq1用户对于dba_objects的权限,也就是对象定义者的权限。

为了进一步证明结果的准确性,下面将继续进行实验变化来演示

当定义者权限失去时,即使调用者拥有权限也是无用的(也就是说wjq1用户没有访问dba_objects的权限,wjq2用户有访问dba_objects的权限)

回收了wjq1用户上的select any dictionary权限,此时wjq1对dba_objects对象权限消失;然后,赋予wjq2用户select any dictionary权限,这样wjq2就能访问dba_objects了

SYS@seiang11g>revoke select any dictionary from wjq1;

Revoke succeeded.

WJQ1@seiang11g>select count(*) from dba_objects;

select count(*) from dba_objects

                     *

ERROR at line 1:

ORA-00942: table or view does not exist

SYS@seiang11g>

SYS@seiang11g>grant select any dictionary to wjq2;

Grant succeeded.

WJQ2@seiang11g>select count(*) from dba_objects;

  COUNT(*)

----------

     86994

WJQ2@seiang11g>exec wjq1.proc_wjq1;

BEGIN wjq1.proc_wjq1; END;

           *

ERROR at line 1:

ORA-06550: line 1, column 12:

PLS-00905: object WJQ1.PROC_WJQ1 is invalid

ORA-06550: line 1, column 7:

PL/SQL: Statement ignored

通过上面的实验结果发现:wjq2用户拥有dba_objects对象访问权限,同时也有执行proc_wjq1的权限,但是执行的时候却报错,认为对象无效。这是为什么呢?唯一的原因就是因为wjq1用户失去了dba_objects对象的权限,而wjq2在调用proc_wjq1时使用的是dba_objects的权限。

以上案例一的实验介绍了Oracle在存储过程中使用的权限配置的“定义者权限”。简单的说,当执行一个程序体(存储过程、函数和包等)的时候,方法体内部使用的权限体系为当前该程序体定义者的权限体系,而与调用方法的用户无关。存储过程proc_wjq1无论是哪一个用户执行,权限体系都是该存储过程的定义者wjq1的权限。

定义者权限是Oracle使用的默认权限选择方式,在使用的时候很方便。调用者只要拥有简单的对象执行权限就可以了,无需顾及自己是否拥有权限访问方法中使用的对象。

案例一对定义者权限通过实验进行了分析,调用者权限的含义就相对容易理解了。调用者权限体系就是执行方法体的时候,使用的权限按照调用者权限体系来判断。一个方法的执行,调用者除了要拥有执行该方法的权限,还要拥有该方法中使用对象的权限才可以。

 

下面案例二通过实验对调用者权限作出详细的分析:

案例二:调用者权限

接着上面案例一的实验环境。注意,此时wjq1用户没有select any dictionary权限,而wjq2有。

WJQ1@seiang11g>create or replace procedure proc_wjq1_1 is

  2  i number;

  3  begin

  4     select count(*) into i from dba_objects;

  5     dbms_output.put_line(to_char(i));

  6  end;

  7  /

Warning: Procedure created with compilation errors.

WJQ1@seiang11g>

WJQ1@seiang11g>select name,line,text from user_errors;

NAME                  LINE TEXT

--------------- ---------- --------------------------------------------------

PROC_WJQ1_1              4 PL/SQL: ORA-00942: table or view does not exist

PROC_WJQ1_1              4 PL/SQL: SQL Statement ignored 

查看报错信息,还是因为wjq1没有dba_objects的权限,所以创建过程失败。

此时,如果在方法定义上加入authid current_user关键字,就可以将存储过程变化为调用者权限。

WJQ1@seiang11g>create or replace procedure proc_wjq1_1 authid current_user is

  2  i number;

  3  begin

  4     select count(*) into i from dba_objects;

  5     dbms_output.put_line(to_char(i));

  6  end;

  7  /

Warning: Procedure created with compilation errors.

WJQ1@seiang11g>

WJQ1@seiang11g>select name,line,text from user_errors;

NAME                  LINE TEXT

--------------- ---------- --------------------------------------------------

PROC_WJQ1_1              4 PL/SQL: ORA-00942: table or view does not exist

PROC_WJQ1_1              4 PL/SQL: SQL Statement ignored 

显然,还在因为wqj1用户没有权限访问dba_objects而报错,毕竟不管是什么体系,wjq1目前是没有对象权限的创建过程是不会成功的。不过,为了实验成功,还是要让wjq1能顺利创建proc_wjq1_1过程。

SYS@seiang11g>grant select any dictionary to wjq1;

Grant succeeded.

WJQ1@seiang11g>create or replace procedure proc_wjq1_1 authid current_user is

  2  i number;

  3  begin

  4     select count(*) into i from dba_objects;

  5     dbms_output.put_line(to_char(i));

  6  end;

  7  /

Procedure created. 

WJQ1@seiang11g>

WJQ1@seiang11g>grant execute on proc_wjq1_1 to wjq2;

Grant succeeded.

切换到wjq2用户,注意此时它是拥有select any dictionary权限的。

WJQ2@seiang11g>select count(*) from dba_objects;

  COUNT(*)

----------

     86995

WJQ2@seiang11g>exec wjq1.proc_wjq1_1;

86995

PL/SQL procedure successfully completed. 

此时,wjq2执行过程成功。因为此时wjq1和wjq2都拥有select any dictionary权限,所以即使在调用者权限下,也是会成功的。此时,如果收回wjq2上的权限,结果会如何呢?

SYS@seiang11g>revoke select any dictionary from wjq2;

Revoke succeeded.

WJQ2@seiang11g>select count(*) from dba_objects;

select count(*) from dba_objects

                     *

ERROR at line 1:

ORA-00942: table or view does not exist

WJQ2@seiang11g>exec wjq1.proc_wjq1;

BEGIN wjq1.proc_wjq1; END;

           *

ERROR at line 1:

ORA-06550: line 1, column 12:

PLS-00905: object WJQ1.PROC_WJQ1 is invalid

ORA-06550: line 1, column 7:

PL/SQL: Statement ignored

此时,就看出调用者权限的差异了。wjq1始终有dba_objects的权限,而wjq2在之后被回收了select any dictionary的权限。如果是定义者权限,wjq2调用proc_wjq1_1是没有问题的。但是此时报错,说明此处使用的是wjq2的调用者权限。

       通过上述两个案例,分别通过实验对定义者权限和使用者权限进行了分析,想必大家已经有了比较深刻的认识和理解了,但是很多时候,我们都会使用存储过程Procedure来实现一些脚本功能。通过Procedure来实现一些数据库相关的维护、开发工作,可以大大提高我们日常工作效率。下面数据库运维过程中有这样一种情况需要我们DBA去处理,实际的问题这样的:


      同一个数据库中有多个Schema的内容相同,用于不同的测试目的。一些开发同步任务促使编写一个程序来实现Schema内部或者之间对象操作。从软件版本角度看,维护一份工具脚本是最好的方法,可以避免由于修改造成的版本错乱现象。如何通过一个存储过程脚本,在不同Schema下执行效果不同就成了我们需要考虑的问题?


       将上述问题简化如下:在Schema A里面包括一个存储过程Proc,A中还有一张数据表T1。在Proc代码中,包括了对表T1的操作内容。而Schema B中也存在一个数据表T1,并且B拥有一个名为Proc的私有同义词synonym指向A.Proc。问题是如何让Proc根据执行的Schema的不同,访问不同Schema中数据表?换句话说,就是如果是Schema A调用Proc程序包,操作的就是Schema A里面的数据表T1。如果B调用Proc程序包,就操作Schema B里面的数据表T1。

为了对上述问题有一个明确的处理方法,下面通过以下示例进行模拟实验:

SYS@seiang11g>select * from v$version;

BANNER

--------------------------------------------------------------------------------

Oracle Database 11g Enterprise Edition Release 11.2.0.4.0 - 64bit Production

PL/SQL Release 11.2.0.4.0 - Production

CORE    11.2.0.4.0      Production

TNS for Linux: Version 11.2.0.4.0 - Production

NLSRTL Version 11.2.0.4.0 - Production

SYS@seiang11g>create user wjq1 identified by wjq1 default tablespace seiang;

User created.

SYS@seiang11g>create user wjq2 identified by wjq2 default tablespace seiang;

User created.

SYS@seiang11g>grant connect,resource,create procedure,create synonym to wjq1,wjq2;

Grant succeeded.

SYS@seiang11g>select * from dba_sys_privs where grantee in ('WJQ1','WJQ2');

GRANTEE                        PRIVILEGE                                ADM

------------------------------ ---------------------------------------- ---

WJQ1                           CREATE SYNONYM                           NO

WJQ2                           UNLIMITED TABLESPACE                     NO

WJQ2                           CREATE SYNONYM                           NO

WJQ1                           UNLIMITED TABLESPACE                     NO

WJQ2                           CREATE PROCEDURE                         NO

WJQ1                           CREATE PROCEDURE                         NO

6 rows selected. 

在Schema wjq1下面创建数据表和相应的存储过程。

 WJQ1@seiang11g>create table tab_wjq(name varchar2(20));

Table created.

WJQ1@seiang11g>create or replace procedure proc_wjq1(v_name varchar2) is

  2  begin

  3     insert into tab_wjq values(v_name);

  4     commit;

  5  end proc_wjq1;

  6  /

Procedure created.

Schema wjq1进行执行存储过程

WJQ1@seiang11g>exec proc_wjq1('wjq');

PL/SQL procedure successfully completed.

WJQ1@seiang11g>select * from tab_wjq;

NAME

--------------------

wjq 

将过程proc_wjq1的权限赋予Schema wjq2

 WJQ1@seiang11g>grant execute on proc_wjq1 to wjq2;

Grant succeeded. 

另外创建Schema wjq2数据表对象,并且包括同义词对象。

 WJQ2@seiang11g>create table tab_wjq(name varchar2(20));

Table created.

WJQ2@seiang11g>create synonym proc_wjq1 for wjq1.proc_wjq1;

Synonym created.

WJQ2@seiang11g>select * from user_synonyms;

SYNONYM_NAME    TABLE_OWNER     TABLE_NAME           DB_LINK

--------------- --------------- -------------------- ------------------------------

PROC_WJQ1       WJQ1            PROC_WJQ1 

进行默认情况测试,在Schema wjq2中调用存储过程proc_wjq1,查看操作的是哪一个Schema下的数据表

WJQ2@seiang11g>exec proc_wjq1('seiang');

PL/SQL procedure successfully completed.

WJQ2@seiang11g>select * from tab_wjq;

no rows selected

Schema wjq2中数据表tab_wjq没有数据,查看Schema wjq1中数据表情况:

WJQ1@seiang11g>select * from tab_wjq;

NAME

--------------------

wjq

seiang 

上述实验说明:在默认情况下,不同Schema对象调用相同存储过程,其中涉及到的对象都是相同的。也就是Oracle存储过程中的“定义者权限”。一旦用户拥有执行存储过程的权限,就意味着在执行体中,使用的是定义者的权限体系。

       那么这个问题似乎是没有办法。执行体指向的是Schema wjq1的数据表tab_wjq。

与定义者权限对应的就是“调用者权限”。也就说,对用户是否可以执行该程序体中的对象,完全取决于执行调用用户系统权限和对象权限(注意:非角色权限)。大胆的猜想,如果使用调用者权限,从执行用户权限角度看,是不是可以直接访问自己Schema中的对象了?下面通过实验进行验证:

 WJQ1@seiang11g>create or replace procedure proc_wjq1(v_name varchar2) authid current_user is

  2  begin

  3     insert into tab_wjq values(v_name);

  4     commit;

  5  end proc_wjq1;

  6  /

Procedure created.

在用户wjq1中进行实验,结果:

WJQ1@seiang11g>exec proc_wjq1('wjqbest');

PL/SQL procedure successfully completed.

WJQ1@seiang11g>select * from tab_wjq;

NAME

--------------------

wjq

seiang

wjqbest

转换到用户wjq2中,进行实验:

 WJQ2@seiang11g>exec proc_wjq1('seiangbest');

PL/SQL procedure successfully completed.

WJQ2@seiang11g>select * from tab_wjq;

NAME

--------------------

seiangbest 

从上面的实验结果可以发现:在调用者权限模式下,可以实现调用Schema下数据表优先的效果。如果此时Schema wjq2中没有数据表tab_wjq,结果又会如何呢?

 WJQ2@seiang11g>drop table tab_wjq;

Table dropped.

WJQ2@seiang11g>exec proc_wjq1('hahaha');

BEGIN proc_wjq1('hahaha'); END;

*

ERROR at line 1:

ORA-00942: table or view does not exist

ORA-06512: at "WJQ1.PROC_WJQ1", line 3

ORA-06512: at line 1

如果wjq2用户拥有wjq1用户下的数据表tab_wjq的权限,结果又会如何呢?

 WJQ1@seiang11g>grant all on tab_wjq to wjq2;

Grant succeeded.

WJQ2@seiang11g>select * from wjq1.tab_wjq;

NAME

--------------------

wjq

seiang

wjqbest

WJQ2@seiang11g>exec proc_wjq1('hahaha');

BEGIN proc_wjq1('hahaha'); END;

*

ERROR at line 1:

ORA-00942: table or view does not exist

ORA-06512: at "WJQ1.PROC_WJQ1", line 3

ORA-06512: at line 1

从上面的结果发现,即使wjq2拥有wjq1下数据表tab_wjq的权限,在使用调用者权限时,也是只能操作自己Schema下的对象。所以定义者权限和调用者权限,是Oracle存储过程中两个重要的概念对象,一些麻烦场景下应用往往有不错的效果。

感谢各位的阅读!关于“Oracle中定义者权限和调用者权限的示例分析”这篇文章就分享到这里了,希望以上内容可以对大家有一定的帮助,让大家可以学到更多知识,如果觉得文章不错,可以把它分享出去让更多的人看到吧!


文章标题:Oracle中定义者权限和调用者权限的示例分析
本文来源:http://pwwzsj.com/article/joejep.html