呼叫者許可權與定義者許可權的pl/sql子程式

hanson發表於2019-03-25
對於pl/sql子程式的呼叫來說,具有兩種方式:定義者許可權和呼叫者許可權。
所謂定義者許可權,表示的是在執行pl/sql子程式的時候,參考的是建立該pl/sql子程式的使用者所擁有的許可權。同時,pl/sql子程式在執行時,對於牽涉到的表或者其他物件,也都參考建立該pl/sql子程式的使用者所擁有的物件。而執行該pl/sql子程式的使用者不需要具有訪問建立該pl/sql子程式的使用者下的表的許可權。預設情況下,pl/sql子程式都以定義者許可權來執行。

比如:
SQL> connect / as sysdba
已連線。
SQL> create user u1 identified by u1;

使用者已建立

SQL> grant create session to u1;

授權成功。

SQL> connect u1/u1
已連線。
SQL> select last_name from hr.employees where employee_id=101;
select last_name from hr.employees where employee_id=101
                         *
ERROR 位於第 1 行:
ORA-00942: 表或檢視不存在

SQL> connect hr/hr
已連線。
SQL> CREATE OR REPLACE PROCEDURE p_get_lastname
  2  (v_employee_id IN employees.employee_id%TYPE,
  3  v_last_name OUT employees.last_name%TYPE) IS
  4  BEGIN
  5    SELECT last_name
  6    INTO v_last_name
  7    FROM employees
  8    WHERE employee_id = v_employee_id;
  9  END;
 10  /

過程已建立。

SQL> grant execute on p_get_lastname to u1;

授權成功。

SQL> connect u1/u1
已連線。
SQL> var ls_lastname varchar2(50);
SQL> exec hr.p_get_lastname(101,:ls_lastname);

PL/SQL 過程已成功完成。

SQL> print ls_lastname;

LS_LASTNAME
----------------------------------------------
Kochhar

可以很明顯看到,定義者許可權中,u1沒有許可權檢視hr.employees表裡的資料,但是u1具有執行hr.p_get_lastname的許可權,從而它可以獲取hr.employees表裡的記錄。

而定義者許可權則不同。它在執行pl/sql子程式的時候,參考的是執行者的許可權。同時,pl/sql子程式在執行時,對於牽涉到的表或者其他物件,也都參考執行該pl/sql子程式的使用者所擁有的物件。
比如:
SQL> connect / as sysdba
已連線。
SQL> create user u2 identified by u2 ;

使用者已建立

SQL> grant create session to u2;

授權成功。

SQL> connect hr/hr
已連線。
SQL> CREATE OR REPLACE PROCEDURE p_get_lastname2
  2  (v_employee_id IN employees.employee_id%TYPE,
  3  v_last_name OUT employees.last_name%TYPE)
  4  authid current_user
  5  IS
  6  BEGIN
  7    SELECT last_name
  8    INTO v_last_name
  9    FROM employees
 10    WHERE employee_id = v_employee_id;
 11  END;
 12  /

過程已建立。

注意,這裡新增的authid current_user就表示該儲存過程為呼叫者許可權。

SQL> grant execute on p_get_lastname2 to u2;

授權成功。

SQL> connect u2/u2
已連線。
SQL> var ls_lastname varchar2(50);
SQL> exec hr.p_get_lastname2(101,:ls_lastname);
BEGIN hr.p_get_lastname2(101,:ls_lastname); END;

*
ERROR 位於第 1 行:
ORA-00942: 表或檢視不存在
ORA-06512: 在"HR.P_GET_LASTNAME2", line 7
ORA-06512: 在line 1

可以看的很清楚,這裡的錯誤為:ORA-00942: 表或檢視不存在。實際也就是hr.p_get_lastname2裡訪問的employees表不存在於當前u2使用者下。

SQL> connect / as sysdba
已連線。
SQL> grant create table to u2;

授權成功。

SQL> alter user u2 quota 5M on users;

使用者已更改。

SQL> connect u2/u2
已連線。

SQL> create table employees(employee_id number,last_name varchar2(50)) tablespace users;

表已建立。

SQL> insert into employees values(101,'hansijie');

已建立 1 行。

SQL> commit;

提交完成。

SQL> exec hr.p_get_lastname2(101,:ls_lastname);

PL/SQL 過程已成功完成。

SQL> print ls_lastname;

LS_LASTNAME
-------------------------------------------------
hansijie

可以看到,當我在u2下建立了employees表以後,就會訪問到u2下的employees表裡的記錄了。

對於定義者許可權的pl/sql子程式來說,通過角色傳入的許可權是不能作用於儲存過程裡面的。比如:
SQL> create user red identified by red;

使用者已建立

SQL> grant dba to red;

授權成功。

SQL> connect red/red
已連線。
SQL> create or replace procedure p_test
  2  is
  3  begin
  4     dbms_utility.exec_ddl_statement('grant dba to u1');
  5  end;
  6  /

過程已建立。

SQL> exec p_test;
BEGIN p_test; END;

*
ERROR 位於第 1 行:
ORA-01031: 許可權不足
ORA-06512: 在"SYS.DBMS_SYS_SQL", line 826
ORA-06512: 在"SYS.DBMS_SQL", line 32
ORA-06512: 在"SYS.DBMS_UTILITY", line 550
ORA-06512: 在"RED.P_TEST", line 4
ORA-06512: 在line 1

這時可以看到,說的很清楚,許可權不足。但是red使用者已經具有了dba許可權了,為何還會報許可權不足呢?這就是因為這是一個定義者許可權的pl/sql子程式,在執行grant dba to u1的時候,不能獲得dba這個角色所傳遞過來的許可權。你可以把該儲存過程改為呼叫者許可權,表示參考呼叫者所擁有的許可權。

SQL> create or replace procedure p_test
  2  authid current_user
  3  is
  4  begin
  5     dbms_utility.exec_ddl_statement('grant dba to u1');
  6  end;
  7  /

過程已建立。

SQL> exec p_test;

PL/SQL 過程已成功完成。

這時就能正確執行了。



來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/9842/viewspace-329702/,如需轉載,請註明出處,否則將追究法律責任。

相關文章