1 前言
數(shù)據(jù)訪問權限控制,是一個古老而又實際的問題。
在大部份系統(tǒng)中,權限控制主要定義為模塊進入權限的控制和數(shù)據(jù)列訪問權限的控制(如:某某人可以進入某個控制,倉庫不充許查看有關金額的字段等等)。
但在某些系統(tǒng)中,權限控制又必須定義到數(shù)據(jù)行訪問權限的控制,此需求一般出現(xiàn)在同一系統(tǒng),不同的相對獨立機構使用的情況。(如:集團下屬多個子公司,所有子公司使用同一套數(shù)據(jù)表,但不同子公司的數(shù)據(jù)相對隔離)
當然,絕大多數(shù)人會選擇在View加上Where子句來進行數(shù)據(jù)隔離。此方法編碼工作量大、系統(tǒng)適應用戶治理體系的彈性空間較小,一旦權限邏輯發(fā)生變動,就可能需要修改權限體系,導致所有的View都必須修改。
本文探討的使用Oracle提供的Policy治理方法來實現(xiàn)數(shù)據(jù)行的隔離。
非凡感謝javac兄提出的此解決方案!
2 實現(xiàn)
2.1 Oracle Policy的簡單說明
Policy應用于數(shù)據(jù)行訪問權限控制時,其作用簡而言之,就是在查詢數(shù)據(jù)表時,自動在查詢結果上加上一個Where子句。假如該查詢已有where子句,則在該Where子句后面加上"And ..."。
由Oracle Policy自動加入的Where子句的內(nèi)容,通常由一個函數(shù)來實現(xiàn)。而進行數(shù)據(jù)行訪問權限控制算法實現(xiàn)的結果,也是通過該函數(shù)返回。
2.2 Oracle Policy的語法簡述
2.2.1 新增Policy
Dbms_Rls.Add_Policy(Object_Schema --數(shù)據(jù)表(或視圖)所在的Schema名稱
,Object_Name --數(shù)據(jù)表(或視圖)的名稱
,Policy_Name --POLICY的名稱,主要用于將來對Policy的治理
,Function_Schema --返回Where子句的函數(shù)所在Schema名稱
,Policy_Function --返回Where子句的函數(shù)名稱
,Statement_Types --要使用該Policy的DML類型,如'Select,Insert,Update,Delete'
,Update_Check --僅適用于Statement_Type為'Insert,Update',值為'True'或'False'
,Enable --是否啟用,值為'True'或'False'
);
注:假如Update_Check設為'True',則用戶插入的值不符合Policy_Function返回條件時,該DML執(zhí)行返回錯誤信息。
2.2.2 刪除Policy
Dbms_Rls.drop_policy(object_schema --要刪除的Policy所在的Schema
,object_name --要刪除Policy的數(shù)據(jù)表(或視圖)名稱
,policy_name --要刪除的Policy名稱
);
2.2.3 設定Policy狀態(tài)
Dbms_Rls.Enable_Policy(object_schema --要刪除的Policy所在的Schema
,object_name --要刪除Policy的數(shù)據(jù)表(或視圖)名稱
,policy_name --要刪除的Policy名稱
,Enable --是否啟用,值為'True'或'False'
);
2.3 Policy使用特性及使用建議
● 一個數(shù)據(jù)表(或視圖)可以有多個Policy,但Policy的名稱在整個Schema范圍內(nèi)不答應重復。
● 假如將Policy指定到視圖,則刪除Policy后,應重新編譯該視圖,否則User_Updatable_Columns系統(tǒng)字典表返回的是否可新增修改刪除的信息可能會全部為“NOT”。
● 通過Policy可以限制用戶對數(shù)據(jù)表記錄的操作范圍。假如Policy加在數(shù)據(jù)表,則由于前臺涉及的數(shù)據(jù)源(通常是視圖)往往涉及許多張數(shù)據(jù)表,權限控制難度很大,建議將Policy加在視圖。
3 Oracle Policy 應用實例
--3.1 創(chuàng)建測試數(shù)據(jù)表
Create Table T_Policy(T1 Varchar2(10),T2 Number(10));
--3.2 創(chuàng)建測試的Policy函數(shù)
CREATE OR REPLACE Function Fn_GetPolicy (P_Schema In Varchar2
,P_Object In Varchar2)
Return Varchar2
Is
Begin
Return 'T2=10';
End;
--3.3 插入測試數(shù)據(jù)
Insert Into T_Policy Values('a',10);
Insert Into T_Policy Values('b',10);
Insert Into T_Policy Values('c',20);
Commit;
--3.4 加入Policy
Begin
Dbms_Rls.Add_Policy(Object_Schema =>'Scott'
,Object_Name =>'T_Policy'
,Policy_Name =>'T_TestPolicy'
,Function_Schema =>'Scott'
,Policy_Function =>'Fn_GetPolicy'
,Statement_Types =>'Select,Insert,Update,Delete'
,Update_Check =>'True'
,Enable =>'True'
);
End;
--3.5 測試Policy
Select * From T_Policy;
Insert Into T_Policy Values ('d',10);
Insert Into T_Policy Values ('d',20);
Commit;
--3.6 查看Policyy設定情況
Select * From user_policies;
--重要提示:執(zhí)行Dbms_Rls.Add_Policy時,必須將執(zhí)行Dbms_Rls包執(zhí)行的權限授予Scott。
測試時也可能使用其它Schema,最簡單的方法是將測試的Schame設為“DBA”權限。