利用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

 

 

你可能感兴趣的:(数据库,schema,function,table,Access,insert)