1. 程式人生 > >Oracle Serucity — Oracle應用上下文

Oracle Serucity — Oracle應用上下文

--Application Context

應用上下文是一個具有只讀屬性的記憶體容器,在應用程式中可以顯式或者隱式的使用這些屬性;

使用應用上下文非常簡單,就好像是你把一個經常使用的電話號碼存在電話本中,當你想使用時很容易找到它;

上下文擁有的記憶體區域叫一個名稱空間,名稱空間中有已命名的屬性,每個屬性都可以儲存一個字串的值;感覺像是cookie;

應用上下文名稱空間標示一個應用上下文,也就是它們是互相獨立的,比如有兩個名稱空間分別叫HRAPP和OEAPP,分別代表了人力資源(Human Resources)和訂單輸入(Order Entry)應用程式;

使用名稱空間的意義想必都很清楚,就像c#中的名稱空間,java中的包,和oracle中的schema一樣,不同名稱空間下可以有相同的物件或者屬性;

-- Namespace

一個名稱空間應該是唯一的,每一個上下文在它自己的名稱空間中建立;在幻燈片中就是建立了一個hrapp的上下文;

當一個上下文被建立,就會分配相應的記憶體區域,並且要關聯一個包;這個包是唯一被允許設定上下文屬性的包;幻燈片中的dbms_session.set_context設定屬性的過程只能在這個包中完成;

幻燈片中給hrapp上下文中的emp_id屬性設定了一個值叫v_emp_id;

-- Using the Application Context

那麼怎麼使用應用上下文呢?

雖然使用應用程式上下文的主要好處是提高效能,但是上下文還可以用於其它Oracle資料庫的安全功能,如虛擬專用資料庫(VPD),之後會講到;

使用應用上下文,可以通過上下文屬性來完成以下功能:

1.在使用者登入時授權:當用戶登入時驗證的使用者的IP地址;

2.設定上下文屬性所使用的細粒度訪問控制(FGAC,也會在之後講到):會話屬性可以被用於限制使用者訪問的記錄;比如在訂單輸入應用程式,使用者可以通過設定與當前使用者的使用者號對應的上下文屬性只能訪問自己的訂單;因為上下文設定和使用的方式,可以無需更改應用程式來實現FGAC。

3.設定在應用程式中使用的屬性:在這種情況下,設定的屬性作為上下文的一部分,而不是從一個表讀取屬性;例如,如果公司員工的數量在應用程式經常被使用,則可以建立一個包含僱員號對應的上下文屬性,而不是每次都去從員工表中彙總得到;

-- Setting the Application Context

這個包一般是由應用程式或者登陸觸發器呼叫的;包裡面設定的屬性一般都是經常被應用程式訪問的;

從而體現出了上下文的效能,總是從記憶體中獲取值,而不是通過SQL語句或者系統呼叫獲得;

USERENV上下文是一個內建的特殊的上下文,USERENV裡面的值經常被用於填充v$session和v$process檢視;並且它對所有的應用程式都是可用的;

-- Application Context Data Sources

上下文可以根據資料的來源分類四類:

1.Built-in Context:內建的上下文叫USEREVN,主要包括幾種型別的屬性:(檢視sys_context函式並測試)

1.客戶端屬性:例如客戶端IP;

2.使用者屬性:例如代理,會話和作業系統的登入使用者名稱等;

3.認證資訊:認證型別,作業系統和語言設定;

2.Local Application Contexts:在FGAC的應用中可以查詢任何資料庫物件的屬性,比如可以從HR.EMPLOYEES表中得到使用者的名稱和部門資訊;也可以從一個儲存過程或者函式中得到返回值;

3.Externalized Application Contexts:外部初始化應用程式上下文的特徵是使用外部資源,例如OCI呼叫;語法為:CREATE CONTEXT external USINGext_package INITIALIZED EXTERNALLY;

4.Global Application Contexts:組織集中化的使用者資訊和管理使用LDAP或者活動目錄,Oracle中類似的是OID(Oracle Internet Directory),應用程式上下文屬性值可以儲存在OID中;建立語法:CREATE CONTEXT hrgapp USING hr_g_contextINITIALIZED GLOBALLY;

-- Implement a Local Context

第一步建立的上下文要跟第二步建立的包關聯,從而保證上下文的屬性只能通過這個包來設定;

-- Create an Application Context

CREATE CONTEXT HRAPP USING PKG_HR_CONTEXT;

上下文都屬於sys使用者,可以通過dba_context資料字典檢視(schema列表示包所屬的架構);

設定上下文的屬性只能通過兩種途徑:1.CREATE CONTEXT時候指定的包;2.FGAC中策略關聯的函式;

使用DBMS_SESSION.SET_CONTEXT設定的屬性的生命週期是:被reset了或者使用者退出會話了;

OPM(Oracle Policy Manager)是一個使用者管理應用上下文,FGAC策略,Oracle LabelSecurity策略圖形化的介面;也可以使用EM訪問(Server->Security);

-- Create a PL/SQL Package

CREATE OR REPLACE PACKAGE pkg_hr_context IS

  1. PROCEDURE set_emp_id;

END pkg_hr_context;

CREATE OR REPLACE PACKAGE BODY pkg_hr_context IS

  1. PROCEDURE set_emp_id IS
  2. v_emp_id NUMBER;
  3. BEGIN
  4. SELECTemployee_id INTO v_emp_id FROM hr.employees WHERE email = sys_context('USERENV','SESSION_USER');
  5. dbms_session.set_context('hrapp','emp_id', v_emp_id);
  6. EXCEPTION
  7. WHENno_data_found THEN
  8. dbms_session.set_context('hrapp','emp_id', 0);
  9. END;

END pkg_hr_context;

-- Call the Package

CREATE OR REPLACE TRIGGER tgr_hr_context_logon

  1. AFTER logon ON DATABASE

BEGIN

  1. pkg_hr_context.set_emp_id();

END;

儘管登陸觸發器不是必須的,因為應用程式可以在任何時候初始化上下文,但是強烈推薦在使用者訪問資料之前設定上下文;

如果所有使用者都用自己的名稱登陸,那麼可以用[ON DATABASE],如果都統一使用一個賬戶的話,可以使用[ON username.SCHEMA];

-- Read the Context Attribute

conn / AS SYSDBA

SELECT sys_context('HRAPP', 'EMP_ID') FROM dual; -- 0

CREATE USER sking IDENTIFIED BY oracle;

GRANT CONNECT TO sking;

GRANT SELECT ON hr.employees TO sking;

conn sking/oracle

SELECT sys_context('HRAPP', 'EMP_ID') FROM dual; -- 100

?可以實現部門領導檢視部門員工資訊的邏輯;

SELECT employee_id, first_name, phone_number, job_id, salary FROMhr.employees WHERE manager_id = sys_context('hrapp', 'emp_id');

-- SYS_CONTEXT函式,檢視ONLINE Help

獲得客戶端IP:SELECT sys_context('USERENV', 'IP_ADDRESS') FROMdual;

獲得當前會話的使用者名稱:SELECT sys_context('USERENV', 'SESSION_USER') FROMdual;

獲得客戶端的使用者名稱:SELECT sys_context('USERENV', 'OS_USER') FROM dual;

-- Application Context AccessedGlobally,可全域性訪問的應用上下文

預設的,應用上下文所使用的記憶體區域是從PGA中分配的;在許多應用程式架構中,都是由中間層應用程式幫助應用程式使用者來管理連線池;使用者在應用程式中驗證後,然後使用一個單一的身份登入到資料庫,並保持所有的連線(其實就是一個長連線);

在連線池的環境中,一般任何使用者都有可能使用任何一個連線,在這種環境中,不可能由會話相關的安全應用上下文來維護應用程式的屬性,因為對於每一個會話來說上下文都是私有的;同樣的,應用程式沒有會話模式,所以使用者可以使用任何會話;

全域性訪問的應用上下文是一種安全的應用程式上下文,它可以在信任的會話之間共享;它為什麼能夠被共享?因為上下文的記憶體區是在SGA中分配的;中間層應用程式可以使用全域性可訪問的應用上下文來管理程式的安全性和全域性性,因為它允許多個連線來訪問一個或者多個上下文;

它通過連線的重用來提高效能,這些應用程式的上下文被初始化一次,而不用每次都要為單獨的會話進行初始化;

使用DBMS_SESSION.SET_IDENTIFIER介面可以為每一個應用程式新增一個客戶端標示,而每個客戶端只能看到分配給它的應用程式上下文;

因為DBMS_SESSION是授予PUBLIC使用者組的,允許未授權的使用者訪問,所以要防止惡意的呼叫和SQL注入;

-- How the Application ContextAccessed Globally Works

一共有9個步驟要去做,幻燈片中左邊的部分是由使用者來做的,右邊的部分是應用程式做的;

1.啟動應用伺服器,並建立一個連線池;

2.使用者U1通過應用程式登入資料庫;

3.應用伺服器為使用者建立一個session;

1.使用連線池中的連線;

2.呼叫SET_IDENTIFIER給U1使用者的會話指定一個客戶端標示;

3.設定應用上下文;

4.儲存客戶端標示到U1的cookie中;

4.此時應用伺服器可以處理U1的請求了,當應用程式讀取上下文時,就不再包含客戶端標示了,因為在第三步驟已經對會話設定標示了;

5.當應用完成U1的請求:

1.呼叫CLEAR_IDENTIFIER清除標示;

2.把連線交給連線池;

6.使用者U1發起另外一個請求;

7.應用程式處理的方式就不同了,因為本地的cookie儲存了當前的上下文資訊:

1.客戶端從cookie中讀取會話的客戶端標示;

2.從連線池中拿到連線後,呼叫SET_IDENTIFIER直接使用客戶端標示;

8.使用者U1登出;

9.應用程式呼叫CLEAR_CONTEXT來清除應用程式上下文;

--PL/SQL包和過程

主要使用DBMS_SESSION包,相關的過程有:(開啟幫助文件介紹;)

SET_CONTEXT:設定上下文,並且與一個客戶端關聯;

SET_IDENTIFIER(client_id):設定一個用於全域性上下文的標示;client_id是用於設定會話的標示符,這個標示符是任意的;因為標示符通常會被放到瀏覽器的cookie中,所以客戶端識別符號絕對不能含有可能被用來竊取使用者隱私的資訊;它應該是一個隨意的字串或者數字;而且client_id會被審計的;

CLEAR_IDENTIFIER:清除標示;

CLEAR_CONTEXT:清除上下文資訊;

LIST_CONTEXT:列舉上下文資訊;

UNIQUE_SESSION_ID:返回當前連線到資料庫會話的標示符,由SET_IDENTIFIED設定;

-- Implementing theApplication Context Accessed Globally

1.建立全域性可訪問的應用上下文;

2.修改建立會話的程式:

1.設定應用上下文;

2.設定會話客戶端標示符;

3.當請求結束時清除客戶端標示符;

3.修改相同會話處理接下來請求的程式:

1.從cookie中讀取並設定會話的客戶端標示符;

2.當請求結束時清除客戶端標示符;

4.修改當結束會話清除上下文的應用程式;

-- Create the ApplicationContext Accessed Globally

DROP CONTEXT hrapp;

CREATE CONTEXT hrapp USING pkg_hr_context ACCESSED GLOBALLY;

之後的步驟需要在包中實現;因為要結合應用程式,所以無法實驗;

-- Data Dictionary Views

SELECT * FROM dba_context;所有的上下資訊;

SELECT * FROM dba_global_context;是dba_context的子集,只列出了全域性訪問的上下文;

conn sking/oracle

SELECT * FROM session_context/v$context;兩個檢視相同,都是列出當前會話設定的屬性和值;

-- Guidelines

1.從包的外部設定上下文:會報許可權不足的錯誤;

2.效能:如果sys_context引數是引數是常數時,它的工作原理就像一個繫結變數,使遊標共享;

3.在應用程式上下文中的版本:當執行一個語句時,資料庫要獲得上下文的快照,保證查詢過程中的一致性;版本控制不適用於全域性可訪問的應用上下文;

4.並行查詢:如果在一個並行查詢的環境中使用sys_context,會報錯;

5.全域性可訪問的應用上下文不支援RAC;

6.驗證上下文資料來源的合法性:如果上下文的資料來源是使用者輸入的,就有可能被改變導致無法訪問;