10g列掩码与关系视图比较,如何避免Oracle数据库密码出现

你可能了解以前的USERENV函数,它返回会话值,如用户会话ID、语言、以及用户是否拥有数据库管理员权限。虽然由于遗留原因,USERENV函数仍在使用,但在Oracle
8i中,它已被一个新的函数所替代――SYS_CONTEXT。

在前面的文章,我为大家介绍了如何使用Oracle
10g的虚拟私有数据库特征掩藏某列数据TechRepublic的成员BrooklynPennyPincher建议我写一篇关于VPD与关系视图的比较文章。

SYS_CONTEXT不仅能够返回USERENV数据――它还能返回应用程序定义的数据值。应用程序上下文包括一组可以被SYS_CONTEXT返回的名称和匹配数据。例如,如果一个人事应用要返回用户的部门号,可以在应用程序中加入下面这行代码:

前面文章中小技巧的任务是假如department_id的值等于60,那么掩藏报告中的salary和commission_pct列。因为谓词是一个静态值,所以一个关系视图肯定也能够完成同样的任务。

v_dept := SYS_CONTEXT(HR_CONTEXT, DEPT);

列表A显示了使用选择器CASE语句比较depatment_id的值与60的关系的视图,假如相等返回NULL,假如是另外一个值则返回salary。一个类似的CASE语句也可以掩藏commission_pct列的数据。通过只授权访问视图而不是基本标来保护数据。

Oracle 9i中推出的After
Logon数据库触发器能够方便地初始化应用程序上下文中的属性。用户成功登录Oracle后,触发器启动,在指定的数据包中执行一个存储过程查询数据,并通过DBMS_SESSION.SET_CONTEXT过程把它放到上下文中。

但是假如我稍稍改变一下规则,要求掩藏除了用户本部门内的所有工资。这将会怎样?
你的第一想法可能是简单地创建更多的视图- -每个部门一个-
-并且授予每个用户访问对应的视图的权限。有很多理由说明这不是一个好的解决方案,具体如下:

使用这种方法有以下几个好处:

大量的视图可能增加维护负担。新的部门可能要求新的视图,用户必须授予访问许可,当用户改变所在部门时,这些访问许可也必须改变。

・它的性能更强。应用程序上下文数据保存在SGA中,访问它可以避免应用程序查询数据时重复读取磁盘。

视图中实现的查询可能是静态值,而不是绑定变量,因此大量同等重要的查询副本将存储在共享池中。

・它更加安全。它使用一个与上下文有关的单独PL/SQL代码对象,通常是一个数据包来改变或清除上下文。After
Logon触发器正是执行的这个数据包。

应用开发中必须为不同的用户调用不同的视图名,这也是复杂性的一个来源。

・它相当灵活。你可以建立任何你需要的上下文,每个上下文中可包含无限数量的属性-值对。

列表B对前面文章中的VPD策略函数进行了一些修改。取替直接比较部门号60,该示例中使用了SYS_CONTEXT函数来返回用户部门号,然后函数为不同的用户返回一个不同的断言。工资只在满足断言条件的行中显示,假如没有设定部门号,将返回始终为假的断言“1==2”,使得整个报告中的所有工资都被掩藏。

列表A说明了一个叫做HR_CONTEXT_PKG的PL/SQL数据包。它查询当前用户会话应与哪个部门有关,从而初始化HR_CONTEXT上下文。

更加有利的是调用函数SYS_CONTEXT作为查询中一个绑定的变量,只有该查询的一个副本存储在共享池中来处理所有部门。

然后你可以用下面的CREATE
CONTEXT语句建立HR_CONTEXT命名空间,并把它与数据包相关联。

也可以使用SYS_CONTEXT函数以同样的方式构建关系视图,但是应用中的一个不同的视图将可能看到所有的数据。VPD方法将会过滤所有对Employees表的访问,而不管是哪个查询。

CREATE CONTEXT hr_context

这是这两种方法的要害区别:视图设计用来过滤一个应用内的数据,而VPD设计用来答应大量用户组透明的共享同样的数据表,每个人只能看到他自己拥有的数据而不管是何应用。CREATE
OR REPLACE VIEW masked_salary_view

USING HR.HR_CONTEXT_PKG;

AS

下面的代码说明了一个登录触发器,它在用户登录时调用安全数据包为用户初始化上下文。如果定位正确的部门出现错误,触发器将通过一个EXCEPTION处理它。否则,没有部门设置的用户将无法登录。

SELECT first_name, last_name, CASE department_id WHEN 60 THEN NULL
ELSE salary END AS salary, department_id

CREATE OR REPLACE TRIGGER DBT_LogoN

FROM employees

AFTER LogoN

/

ON DATABASE

CREATE OR REPLACE FUNCTION rls_dept (obj_owner IN VARCHAR2, obj_name
IN VARCHAR2)RETURN VARCHAR2 AS deptno NUMBER; predicate
VARCHAR2(200);BEGIN deptno := SYS_CONTEXT(HR_CONTEXT,DEPT); IF deptno
IS NULL THEN predicate := 1=2; ELSE predicate := department_id =
deptno; END IF;

BEGIN

RETURN (predicate);END rls_dept;/

HR.HR_CONTEXT_PKG.INITIALIZE_HR_CONTEXT;

EXCEPTION

WHEN OTHERS THEN

NULL;

END;

/
这样,现在任何应用程序都能够找出当前用户与哪个部门相关联,而不必进行多次逻辑读取,从一个表中查询它。例如:

SELECT SYS_CONTEXT(HR_CONTEXT,DEPT) FROM DUAL;

这行代码将返回当前用户的部门ID。

Bob
Watkins(OCP、MCDBA、MCSE、MCT)是一位有25年经验的计算机专业人士,从事过技术培训师、顾问与数据库管理员等职。

发表评论

电子邮件地址不会被公开。 必填项已用*标注