【Oracle】如何讓一個用戶能夠訪問另外一個用戶下所有的表


根據需求的不同,也分為好幾種方法,且看下文。

先構造基本的環境:創建兩個用戶AA,BB,基本需求為用戶AA能夠訪問用戶BB下所有的表,即用戶AA有對BB下所有的表有“select on”權限。

SYS@zkm> create user aa identified by oracle account unlock;

User created.

SYS@zkm> create user bb identified by oracle account unlock;

User created.

SYS@zkm> grant connect,resource to aa,bb;

Grant succeeded.
SYS@zkm> create table bb.t1(id int);

Table created.

SYS@zkm> create table bb.t2(id int);

Table created.

SYS@zkm> conn aa/oracle
Connected.
AA@zkm> select * from bb.t1;
select * from bb.t1
                 *
ERROR at line 1:
ORA-00942: table or view does not exist

對用戶BB創建了兩張表T1和T2,用戶AA並沒有對這兩張表訪問權限。

根據需求,有方法1:

SYS@zkm> select 'grant select on "'||owner||'"."'||table_name||'" to aa;' grant_sql from dba_tables where owner='BB'; 

GRANT_SQL
--------------------------------------------------------------------------------
grant select on "BB"."T1" to aa;
grant select on "BB"."T2" to aa;

SYS@zkm> grant select on "BB"."T1" to aa;

Grant succeeded.

SYS@zkm> grant select on "BB"."T2" to aa;

Grant succeeded.

SYS@zkm> conn aa/oracle
Connected.
AA@zkm> select * from bb.t1;

no rows selected

AA@zkm> select * from bb.t2;

no rows selected

缺點也很明顯,對於新增加的表用戶AA仍然無權限訪問。

方法2:

回收權限,重新進行新的實驗。

AA@zkm> conn bb/oracle
Connected.
BB@zkm> revoke select on "BB"."T1" from aa;

Revoke succeeded.

BB@zkm> revoke select on "BB"."T2" from aa;

Revoke succeeded.

BB@zkm> conn aa/oracle
Connected.
AA@zkm> select * from bb.t1;
select * from bb.t1
                 *
ERROR at line 1:
ORA-00942: table or view does not exist

方法如下:

SYS@zkm> grant select any table to aa;

Grant succeeded.

SYS@zkm> conn aa/oracle
Connected.
AA@zkm> select * from bb.t1;

no rows selected

AA@zkm> select * from bb.t2;

no rows selected

這種方法對新增加的表也有訪問權限,缺點是除了SYS用戶以外所有用戶的表AA均有訪問權限,由於權限被放大了,也就存在安全隱患。客戶能接受是最方便的辦法了。

方法3:

根據需求,不放大權限,並且對新建的表也有權限訪問的話,目前我只想到用觸發器來實現。先使用方法1對當前現有的表授權訪問權限給AA,編寫觸發器實現BB創建新表后,觸發授權動作達到目的。

回收select any table權限,並使用方法1對已有的表授權訪問權限。

SYS@zkm> revoke select any table from aa;

Revoke succeeded.

SYS@zkm> grant select on "BB"."T1" to aa;

Grant succeeded.

SYS@zkm> grant select on "BB"."T2" to aa;

Grant succeeded.

不過在研究過程還是遇到一個問題,對於觸發器觸發的動作只能是DML操作,不能是DDL或者DCL。grant這個動作屬於DCL操作會報錯。詳細見下文。

BB@zkm> create or replace trigger new_table_grant_tri
  2  after create
  3  on schema
  4  declare
  5     sqlstr varchar2(100);
  6  begin
  7     sqlstr:='grant select on '||ora_dict_obj_name||' to aa';
  8     execute immediate sqlstr;
  9  end;
 10  /

Trigger created.

BB@zkm> create table t3(id int);
create table t3(id int)
*
ERROR at line 1:
ORA-00604: error occurred at recursive SQL level 1
ORA-30511: invalid DDL operation in system triggers
ORA-06512: at line 5

BB@zkm> !oerr ora 30511
30511, 00000, "invalid DDL operation in system triggers" 
// *Cause:  An attempt was made to perform an invalid DDL operation
//          in a system trigger. Most DDL operations currently are not 
//          supported in system triggers. The only currently supported DDL 
//          operations are table operations and ALTER?COMPILE operations. 
// *Action: Remove invalid DDL operations in system triggers.

上網找資料,發現一種技術叫“自治事務”,以前接觸過一下沒在意。
自治事務是在某個會話中獨立開啟一個事務,在其中處理的操作不會影響到同一會話中其他事務未提交的內容。反過來也是,同一會話的事務不會影響自治事務的內容。
於是將觸發器改寫如下:

BB@zkm> CREATE OR REPLACE TRIGGER new_table_grant_tri
  2  after create
  3  ON SCHEMA
  4  DECLARE
  5    PRAGMA AUTONOMOUS_TRANSACTION;
  6    sqlstr varchar2(100);
  7  BEGIN
  8   IF ora_dict_obj_type='TABLE' THEN
  9       sqlstr:='grant select on '||ora_dict_obj_name||' to aa';
 10       execute immediate sqlstr;
 11       COMMIT;
 12   end if;
 13  END;
 14  /

Trigger created.

BB@zkm> create table t3(id int);
create table t3(id int)
*
ERROR at line 1:
ORA-00604: error occurred at recursive SQL level 1
ORA-04020: deadlock detected while trying to lock object BB.T3
ORA-06512: at line 7

目前尚不清楚ORA-4020錯誤產生原因。
換另外一種實現方式,先創建存儲過程,該存儲過程實現對新表授權動作。再創建觸發器,調用該存儲過程。如下:

BB@zkm> create or replace procedure new_table_grant_procedure(v_tabname IN VARCHAR2)
  2  is
  3  sqlstr    VARCHAR2(200);
  4  begin
  5      sqlstr := 'grant select on ' || v_tabname ||' to aa';
  6      execute immediate sqlstr;
  7  end;
  8  /

Procedure created.

BB@zkm> CREATE OR REPLACE TRIGGER new_table_grant_tri
  2  after create
  3  ON SCHEMA
  4  DECLARE
  5    PRAGMA AUTONOMOUS_TRANSACTION;
  6    lv_job NUMBER;
  7  BEGIN
  8   IF ora_dict_obj_type='TABLE' THEN
  9   DBMS_JOB.SUBMIT(lv_job,'new_table_grant_procedure('''||ora_dict_obj_name||''');');
 10       COMMIT;
 11   end if;
 12  END;
 13  /

Trigger created.

BB@zkm> create table t3(id int);

Table created.

BB@zkm> conn aa/oracle
Connected.
AA@zkm> select * from bb.t3;

no rows selected

如果不使用DBMS_JOB.SUBMIT的方式同樣會報錯ORA-4020,待探究。

關於觸發器的其他知識點:

ora_client_ip_address:用於返回客戶端的IP地址
ora_database_name:用於返回當前數據庫名
ora_des_encrypted_password:用於返回DES加密后的用戶口令
ora_dict_obj_name:用於返回DDL操作所對應的數據庫對象名
ora_dict_obj_name_list(name_list_ OUT ora_name_list_t):用於返回字事件中被修改的對象名列表
ora_dict_obj_owner:用於返回DDL操作所對應的對象的所有者名。
ora_dict_obj_ower_list(ower_list OUT ora_name_list_t):用於返回在事件中被修改對象的所有者列表
ora_dict_obj_type:用於返回DDL操作所對應的數據庫對象的類型。
ora_grantee(user_list OUT ora_name_list_t):用於返回授權時事件授權者。
ora_instance_num:用於返回歷程號。
ora_is_alter_column(column_name IN VARCHAR2):用於檢測特定列是否被修改
ora_is_creating_nested_table:用於檢測是否正在建立嵌套表
ora_is_drop_column(column_name IN VARCHAR2):用於檢測特定列是否被刪除
ora_is_servererror(error_number):用於檢測是否返回了特定Oracle錯誤。
ora_login_user:用於返回登錄用戶名
ora_sysevent :用於返回觸發 觸發器的系統時間名。

內容大致以上這些。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM