1. 程式人生 > >Oracle儲存過程物件(package,procedure etc...) 呼叫許可權 ----20180206

Oracle儲存過程物件(package,procedure etc...) 呼叫許可權 ----20180206

在一些技術論壇裡面,常常看到有朋友問這種問題: 為什麼我的使用者具有DBA許可權,卻無法在儲存過程裡面建立一張普通表呢? 
下面就結合具體案例來談談這個問題: 
SQL> conn eric/eric;
Connected.SQL> select * from dba_role_privs where grantee=‘ERIC‘;
 
GRANTEE                        GRANTED_ROLE                   ADM DEF
------------------------------ ------------------------------ --- ---
ERIC                           DBA                            NO  YES
ERIC                           CONNECT                        NO  YES
ERIC                           RESOURCE                       NO  YES
ERIC                           RECOVERY_CATALOG_OWNER         NO  YES
可以看到,使用者eric擁有 DBA 許可權!  
用此使用者建立一個儲存過程:
create or replace procedure p_CreateTable 
as
begin
 execute immediate ‘create table test_tb(id number)‘;
end p_CreateTable;
/
Procedure created.
執行時會發現,系統提示許可權不足(insufficient privileges)!
SQL> exec p_CreateTable;
BEGIN p_CreateTable; END; 
*
ERROR at line 1:
ORA-01031: insufficient privileges
ORA-06512: at "ERIC.P_CREATETABLE", line 3
ORA-06512: at line 1
 由上可以看到,即使擁有DBA role,也不能建立表。即 role在儲存過程中不可見!
查閱資料發現:
Oracle8i以前的版本,所有已編譯儲存物件,包括packages, procedures, functions, triggers, views等,只能以定義者(Definer)身份解析執行;
而Oracle8i及其後的新版本,Oracle引入呼叫者(invoker)許可權,使得物件可以以呼叫者身份和許可權執行。
遇到這種情況,通常解決方法是進行顯式的系統許可權: grant create table to eric;但是,此方法太笨,因為有可能執行一個儲存過程,
需要很多不同許可權(oracle對許可權劃分粒度越來越細)。 
最好的方法是,利用 oracle 提供的方法,在建立儲存過程時,加入 Authid Current_User 條件進行許可權分配。 
create or replace procedure p_CreateTable Authid Current_User 
as 
begin
 execute immediate ‘create table test_tb(id number)‘;
end p_CreateTable;
/
Procedure created.
SQL> exec p_CreateTable;
PL/SQL procedure successfully completed.
SQL> desc test_tb
 Name                                      Null?    Type
 ----------------------------------------- -------- ----------------------------
 ID                                                 NUMBER
 成功啦!!! 
由此可以引申出一個問題: 
如果使用者B要執行A使用者的某儲存過程,傳統的解決方案是: 
A使用者將此儲存過程的執行許可權賦予B使用者:
grant execute on p_test to B; 
在B使用者下建立一個同義詞:
create synonym p_test for a.p_test; 
然後B使用者就可以直接執行p_test了.
但是,如果使用 Authid Current_User 選項,在建立時給呼叫者授權,就簡單多了!