来源《Oracle plsql 程序设计》
写存储过程时经常由于执行权限导致得不到想要的数据,现在详细看一下;
Oracle数据库为PL/SQL程序提供了两种对象许可模型,默认的是定义者权限(AUTHID DEFINER),使用这种模型,存储过程是运行在他的所有者权限下的;
1 定义者权限模型(AUTHID DEFINER)
执行存储过程前要前,程序要先编译并且保存到数据库中。一个程序通常保存在一个模式或者说一个数据库用户下,程序中可能会用到其他用户下的对象。
定义者权限模型的规则
1.程序中的任何外部引用都必须在编译时被解析,所使用的权限是编译时所在模式被直接赋予的权限;
2.在编译存储过程时,数据库角色会被忽略。这个程序需要的所有权限都必须直接授予这个过程的定义者;
3.当执行定义者权限模型编译的过程时,过程执行的sql都是运行于拥有这个过程的模式的权限之下;
4.尽管编译过程需要直接授权,可以把执行程序所需要的EXECUTE权限授予其他模式或角色;
使用定义者权限模型控制对底层数据的访问:
所有的订单处理数据放在OEData模式下;
所有的订单处理代码放在ODCode模式下,且编译Order_Mgt的权限直接授予了OECode,这个包允许下订单和取消订单;
为了保证正确更新订单,不允许除了OEcode以外的其他任何模式直接访问这个表。比如,加入Sam_Sales模式需要关闭旧订单,他不能通过Close_Old_Orders执行删除语句,必须通过调用Order_Mgt.cancel完成删除订单任务。
定义者权限模型的好处
1.能控制对底层结构的访问,保证只能通过专门的程序接口这一种方式修改表内容;
2.由于plsql引擎不必在运行时检查是否有权限,应用程序的性能显著改善;
3.不用担心搞错表;
定义者权限模型的缺点
我的表在哪
开发人员通常使用属于其他模式的表编写代码,并且为这些表或视图创建公有别名,从而隐藏模式信息。然后通过数据库角色授权。,这种做法造成一些问题;
假如组织内部都是通过角色分配对对象的访问权限。有一个accounts表,其实是一个基于其他模式下表的同义词。当在sqlplus中执行如下语句时没有什么问题:
SELECT account#,name FROM accounts;
而在过程中使用这张表时却报错:
CREATE OR REPLACE PROCEDURE show_accounts
IS
BEGIN
FOR rec IN (SELECT account#,name FROM accounts)
LOOP
DBMS_OUTPUT.PUT_LINE(rec.name);
END LOOP;
END;
提示ACCOUNTS必须被定义。
造成问题的原因是accounts实际是属于另一个模式的表,解决问题需要让DBA授权,才能完成任务。
动态SQL和定义者权限
另一个问题出在执行动态sql上,加入有这样一个过程,被用来执行DDL语句:
PROCEDUTE execDDL(ddl_string IN VARCHAR2)
IS
BEGIN
EXECUTE IMMEDIATE ddl_string;
EXCEPTION结果是
WHEN OTHERS
THEN
DBMS_OUTPUT.PUT_LINE('Dynamic SQL Failure:'||SQLERRM);
DBMS_OUTPUT.PUT_LINE(' on statement:"'|| ddl_strint ||'"');
RAISE;
END;
这个程序在自己用户下测试执行没有问题。在COMMON用户下编译后,共享给其他人使用。结果是执行的创建,删除,修改的所有对象都在COMMON用户下,除非创建表时指定了表的模式且COMMON用户有创建任何表的权限。
2 调用者权限模型(AUTHID CURRENT_USER)
当程序使用运行程序的人的权限而不是程序所有者的权限时,应该选用 调用者权限模型 。执行权限模型为调用者的程序,程序中的sql语句的外部引用都会根据调用者的权限进行解析,而不再是根据拥有这个程序或定义这个程序的模式进行解析。
如上图所示,当程序使用的是调用者权限模型编译在一个代码库中,一个东北方的用户执行代码库中的代码时,就会自动使用自己模式下的表。
调用者权限的语法
就是在程序头部IS或者AS关键字之前添加子句AUTHID CURRENT_USER
就可以了。
例如上面的执行DDL语句的程序,用调用者权限定义就是这样:
PROCEDURE execddl(ddl_in in VARCHAR2)
AUTHID CURRENT_USER
IS
BEGIN
EXECUTE IMMEDIATE ddl_in;
END;
关键子AUTHID CURRENT_USER 表明当程序执行时,应该在调用者的权限下执行,而不是定义者权限。
调用者权限的规则和限制
1.调用者模型需要显示指定关键字AUTHID CURRENT_USER,默认是定义者权限模型;
2.调用者权限模型是在程序运行时刻才根据调用者的权限对sql使用的数据库对象进行解析;
3.使用调用者权限模型时,只要调用者权限模型不是从定义者权限程序中调用的,运行时角色就有效;
4.AUTHID子句只能用于一个单独的程序的头部、包规范或者对象类型规范。不能对包里的个别程序或对象类型的方法使用AUTHID子句。所以整个包都是调用者或定义者权限。如果包里需要包含两种执行权限模型,那么就需要使用两个包。
5.调用者权限对外部引用的解析使用于下列语句:
--SELECT 、INSERT、UPDATE、MERGE、DELETE数据操作语言
--LOCK TABLE事务控制语言
--OPEN 和 OPEN FOR 游标控制语句
--EXECUTE IMMEDIATE 和 OPEN FOR USING 动态SQL语句
--使用DBMS_SQL.PARSE解析的SQL语句
6.定义者权限总是在编译时刻解析PL/SQL程序和对象类型方法中的外部引用;
7.可以通过调用者权限修改 对于静态的外部数据元素引用的解析
3.组合权限模型
如果在一个定义者权限模型的程序中调用了一个调用者权限模型的程序,会发生什么:
1.如果是定义者权限的程序 调用 调用者权限的程序 ,被调用的程序执行时使用的是调用程序所拥有的权限;
2.如果是调用者权限的程序 调用 定义者权限的程序, 当被调用的程序运行时使用的是被调用程序所有这拥有的权限。一旦控制返回给调用者,又会恢复调用这权限。
总的来说就是定义者权限 要比 调用者权限 更强。