程序员人生 网站导航

[精]Oracle VPD详解(虚拟专用数据库)

栏目:数据库应用时间:2016-11-11 08:15:21

所谓虚拟专用数据库(VPD)指的是,通过在数据库里进行配置,从而让不同的用户只能查看某 个表里的部份数据。VPD分为以下两个级别。 

  • 行级别:在该级别下,可以控制某些用户只能查看到某些数据行。比如,对销售数据表sales 来讲,每一个销售人员只能检索出他自己的销售数据,不能查询其他销售人员的销售数据。 

  • 列级别:在该级别下,可以控制某些用户不能检索某个表的某个列的值。比如用户HR 下的 employees 表中,含有工资(salary)列,由于该列比较敏感,因此不让其他用户查询该列的值。 其他用户检索该列时,会发现其值全都为空(null )。 

1、基于行的VPD  

基于行的VPD 也叫作Fine-Grained Access Control ,简称 FGAC 。FGAC 通过定义规则实现,规则 的集合叫做FGAC 政策(policy)。如果对某个表设置了 FGAC ,则当用户对该表发出查询或DML 语句时,Oracle 都会根据定义的 FGAC 政策,而自动改写这些SQL 语句。其改写方式为自动在SQL 语句后面添加where条件。 
比如,我们在OE用户下有1个表sales_list ,寄存了所有的销售记录。每一个销售人员只能查询他 自己的销售记录。因而,我们在sales 表上设置FGAC 政策来实现这个业务需求。如果某个销售人员 (假定其登录的用户名为 S0020 )发出下面的查询语句: 
  1. Select * from sales_list ;
Oracle 在履行该语句时,如果发现 sales_list 表上存在FGAC 政策,因而就会根据 FGAC 政策,依照以下方式改写该SQL 语句: 
  1. Select * from sales_list where seller_id='S0020';
对用户来讲,这个添加 where条件的进程是完全透明的,用户其实不知道 Oracle 已改写了他发出的SQL 语句,从而过滤了查询结果。固然,如果该销售人员发出的语句为: 
  1. Select * from sales_list where values>1000 ;
那末,当Oracle 在改写该 SQL 语句时,则会改写为以下情势: 
  1. Select * from sales_list where qty_sold>1000 and seller_id='S0020';
使用FGAC 政策来限定返回记录的方式具有许多优点。比如,不需要改写利用程序、对用户完全透明、集中设置、便于管理等。 
在使用FGAC 时,会触及利用程序上下文(Application Context)的概念,使用利用程序上下文可 以简化FGAC 的实现。利用程序上下文是1个数据库对象,可以把它理解为数据库里的每一个 session 的全局环境变量。1旦用户登录到数据库,从而创建出session 以后,利用程序上下文就在全部 session 的生命周期里可用。在利用程序上下文里可以定义多个属性,并为这些属性设置具体的值。而用户不 能直接修改属性的值,只能通进程序包来修改属性值。利用程序上下文总是由用户sys 具有。 
比如,对前面 sales_list 表的例子来讲。我们可以创建1个利用程序上下文,当用户登录时,将 该用户的ID 号作为1个属性值放入该利用程序上下文中。然后在定义FGAC 政策的时候,将该用户 ID号取出,并作为限定条件短语(也就是where条件语句)返回给 Oracle,从而实现FGAC 。 
Oracle 数据库里,已为每一个 session 都预先建立了1个利用程序上下文:userenv。1旦建立了session ,该 session 就能够使用这个利用程序上下文。在 userenv中已预先定义了1些属性,比如 ip_address、session_user和db_name 等。在获得利用程序上下文里的属性值时,我们使用sys_context 函数。该函数包括两个参数,第1个参数表示利用程序上下文的名称,第2个参数表示要显示的属性 名称。以下所示: 
  1. SQL> select sys_context('userenv','ip_address') "IP",
  2. sys_context('userenv','db_name') "DB" from dual;
  3. IP DB
  4. --------------- ---------
  5. 152.68.32.60 ora10g
我们也能够创建自己的利用程序上下文,以下所示: 
  1. SQL> create or replace context sales_ctx using oe.sales_app_pkg;
在这里,sales_ctx 是利用程序上下文的名称,而 sales_app_pkg 则是用来设置sales_ctx 里属性的程序包。在创建利用程序上下文时,指定的、用来设置其中属性的程序包可以没必要事前存在。但是在为利用程序上下文里设定属性值时,该程序包必须存在,否则报错。如果要删除利用程序上下文,则使用下面的命令: 
  1. SQL> drop context sales _ctx;
创建了利用程序上下文以后,我们就能够在其中设置属性了。在设置具体的利用程序上下文属性时,必须使用Oracle 提供的程序包 dbms_session.set_context 来设置其属性。其使用格式为: 
  1. dbms_session.set_context ('context_name', 'attribute_name', 'attribute_value')
我们只能在程序包里使用dbms_session.set_context,而不能直接在SQL*Plus里调用。以下所示: 
  1. SQL> show user
  2. USER is "SYS"
  3. SQL> exec dbms_session.set_context('sales_ctx','seller_id','S0020');
  4. BEGIN dbms_session.set_context('sales_ctx','seller_id','S0020'); END;
  5. *
  6. ERROR at line 1:
  7. ORA-01031: insufficient privileges
  8. ORA-06512: at "SYS.DBMS_SESSION", line 90
  9. ORA-06512: at line 1
我们创建oe.sales_app_pkg包,以下所示: 
  1. SQL> connect oe/oe
  2. SQL> create or replace package sales_app_pkg is
  3. 2 procedure set_sales_context;
  4. 3 end;
  5. 4 /
  6. SQL> create or replace package body sales_app_pkg is
  7. 2 procedure set_sales_context is
  8. 3 begin
  9. 4 dbms_session.set_context('sales_ctx','seller_id',user);
  10. 5 end;
  11. 6 end;
  12. 7 /
  13. SQL> grant select on sales_list to public;
  14. SQL> grant update on sales_list to public;
  15. SQL> grant execute on sales_app_pkg to public;
把履行oe.sales_app_pkg 程序包的权限赋给所有用户以后,我们可以测试利用程序上下文是不是生效了。 
  1. SQL> connect hr/hr
  2. SQL> exec oe.sales_app_pkg.set_sales_context;
  3. SQL> select sys_context('sales_ctx','seller_id') from dual;
  4. SYS_CONTEXT('SALES_CTX','SELLER_ID')
  5. --------------------------------------------------------------------------------
  6. HR
可以看到,利用程序上下文生效了。接下来,我们创建用于FGAC 规则的函数。 
  1. SQL> create or replace package sales_app_pkg is
  2. 2 procedure set_sales_context;
  3. 3 function where_condition
  4. 4 (p_schema_name varchar2,p_tab_name varchar2)
  5. 5 return varchar2;
  6. 6 end;
  7. 7 /
  8. SQL> create or replace package body sales_app_pkg is
  9. 2 procedure set_sales_context is
  10. 3 v_user varchar2(30);
  11. 4 begin
  12. 5 dbms_session.set_context('sales_ctx','seller_id',user);
  13. 6 end;
  14. 7
  15. 8 function where_condition
  16. 9 (p_schema_name varchar2,p_tab_name varchar2) return varchar2 is
  17. 10 v_seller_id varchar2(100) := upper(sys_context('sales_ctx','seller_id'));
  18. 11 v_where_condition varchar2(2000);
  19. 12 begin
  20. 13 if v_seller_id like 'S%' then
  21. 14 v_where_condition := 'seller_id = ' || '''' || v_seller_id || '''';
  22. 15 else
  23. 16 v_where_condition := null;
  24. 17 end if;
------分隔线----------------------------
------分隔线----------------------------

最新技术推荐