利用DBMS_RLS實現VPD 實例

VPD(virtual Private database):虛擬私有數據庫,從名字上可能不太好理解。
形象地舉個例子:比如我們鋼鐵行業的數據庫,既提供給寶鋼使用,又提供給鞍鋼使用(這個在實際中是不可能的,此處爲了說明問題而已),但是要求寶鋼只能訪問寶鋼的數據,鞍鋼只能訪問鞍鋼的數據。這個時候雖然實際只有一個數據庫,但是我們可以看成兩個數據庫,一個寶鋼的數據庫,一個鞍鋼的數據庫,此所謂虛擬私有數據庫。

實現上面的關鍵在於RLS(row level security) 行級權限控制,實現在於通過dbms_rls包,通過add_policy存儲過程來實現。
下面舉個例子:

--創建演示schema
SQL> create user rls identified by rls;
  
User created
 
--創建一個賬戶表,表示每個客戶的賬號以及對應餘額
SQL> create table rls.accounts(acct_no number not null,cust_id number not null,amount number(15,2));
 
Table created

SQL> select * from rls.accounts;
 
   ACCT_NO    CUST_ID            AMOUNT
---------- ---------- -----------------

--插入數據
SQL> insert into rls.accounts values(111111,123,50000);
 
1 row inserted
 
SQL> insert into rls.accounts values(222222,123,50000);
 
1 row inserted
 
SQL> insert into rls.accounts values(333333,456,50000);
 
1 row inserted
 
SQL> insert into rls.accounts values(444444,789,80000);
 
1 row inserted
 
SQL> commit;
 
Commit complete
 
SQL> select * from rls.accounts;
 
   ACCT_NO    CUST_ID            AMOUNT
---------- ---------- -----------------
    111111        123          50000.00
    222222        123          50000.00
    333333        456          50000.00
    444444        789          80000.00

--創建訪問策略表,表中確定了哪個用戶對那個賬戶有什麼權利
SQL> create table rls.access_policy(am_name varchar2(20),cust_id number,access_type varchar2(1));
 
Table created
 
SQL> insert into rls.access_policy values('SCOTT',123,'S');
 
1 row inserted
 
SQL> insert into rls.access_policy values('SCOTT',123,'I');
 
1 row inserted
 
SQL> insert into rls.access_policy values('SCOTT',123,'D');
 
1 row inserted
 
SQL> insert into rls.access_policy values('SCOTT',123,'U');
 
1 row inserted
 
SQL> insert into rls.access_policy values('SCOTT',456,'S');
 
1 row inserted
 
SQL> insert into rls.access_policy values('SCOTT',789,'S');
 
1 row inserted
 
SQL> insert into rls.access_policy values('HR',456,'I');
 
1 row inserted
 
SQL> insert into rls.access_policy values('HR',456,'D');
 
1 row inserted
 
SQL> insert into rls.access_policy values('HR',456,'U');
 
1 row inserted
 
SQL> insert into rls.access_policy values('HR',456,'S');
 
1 row inserted
 
SQL> commit;
 
Commit complete
 
SQL> select * from rls.access_policy;
 
AM_NAME                 CUST_ID ACCESS_TYPE
-------------------- ---------- -----------
SCOTT                       123 S
SCOTT                       123 I
SCOTT                       123 D
SCOTT                       123 U
SCOTT                       456 S
SCOTT                       789 S
HR                          456 I
HR                          456 D
HR                          456 U
HR                          456 S
 
10 rows selected
 

--創建查詢策略函數,應用上面的rls.access_policy表,只能查看rls.access_policy中存在的對應用戶的cust_id
--注意,該函數有兩個varchar2類型的參數,不能去掉這2個參數,否則執行查詢時報錯:ORA-28112: failed to execute policy function
SQL> create or replace function rls.fn_getPolicy_S(p_schema In varchar2,p_object in varchar2) return
  2  varchar2 is
  3  result varchar2(1000);
  4  begin
  5  result := 'cust_id in (select cust_id from rls.access_policy where am_name=''' || USER||''' and access_type=''S'')';
  6  return result;
  7  end fn_getPolicy_S;
  8  /
 
Function created

--檢驗函數是否正確
SQL> select rls.fn_getPolicy_S('***','XXX') from dual;
 
FN_GETPOLICY_S('SCOTT','XXX')
------------------------------------------------------------------------------------------
cust_id in (select cust_id from sys.access_policy where am_name='SYS' and access_type='S')
 
--添加查詢策略
begin
  -- Call the procedure
  dbms_rls.add_policy(object_schema => 'RLS',
                      object_name => 'ACCOUNTS',
                      policy_name => 'ACC_S',
                      function_schema => 'RLS',
                      policy_function => 'FN_GETPOLICY_S',
                      statement_types => 'SELECT',
                      update_check => TRUE,
                      enable => TRUE
                      );
end;

--以不同用戶登錄,查看對應數據,判斷查詢策略是否起作用;
scott@TESTASM> conn hr/hr;                    
Connected.
hr@TESTASM> select * from rls.accounts;  --hr用戶只能查看到456

   ACCT_NO    CUST_ID     AMOUNT
---------- ---------- ----------
    333333        456      50000

hr@TESTASM> conn scott/tiger
Connected.
scott@TESTASM> select * from rls.accounts;  --scott用戶可以查看123、456、789的賬戶

   ACCT_NO    CUST_ID     AMOUNT
---------- ---------- ----------
    222222        123      50000
    111111        123      50000
    333333        456      50000
    444444        789      80000

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章