Java 持久化/審計和安全
JPA 通常用於具有共享連線池的中層/伺服器環境。連線池允許共享資料庫連線以避免重新連線到資料庫的成本。通常,使用者登入到應用程式,但沒有他們自己的資料庫登入,因為共享資料庫登入用於連線池。這與傳統的兩層應用程式模型不同,在傳統的兩層應用程式模型中,每個使用者都有他們自己的資料庫登入。大多數資料庫提供審計支援來記錄更改並提供基於使用者的安全。但是,在具有共享連線池和 Web 使用者的三層環境中,這通常不起作用。
有幾種審計和安全解決方案
- 為每個應用程式使用者提供一個數據庫使用者 ID,併為每個使用者提供他們自己的資料庫連線。
- 使用公共資料庫使用者 ID,並在應用程式中管理審計和安全。
- 使用資料庫代理身份驗證來允許共享連線池和使用者上下文。
這允許進行基於資料庫使用者的審計和安全。如果每個應用程式使用者都有他們自己的資料庫使用者 ID,則連線不能共享。每個使用者在建立他們的 EntityManager 時都需要建立一個新的資料庫連線。
JPA 沒有關於如何執行此操作的標準,但一些 JPA 提供商允許將 JPA 永續性單元屬性作為 EntityManager 屬性傳遞以配置 EntityManager 連線。如果您的 JPA 提供商不支援此功能,那麼您可以嘗試為每個使用者建立 EntityManagerFactory 以允許傳遞連線屬性。但這可能很昂貴,因此請謹慎操作,確保停用共享快取並將連線池大小設定為 1。
- EclipseLink/TopLink : 透過允許將 JPA 永續性單元屬性傳遞給 EntityManagerFactory.createEntityManager(Map) API 來支援這種模型。應用程式可以傳遞“javax.persistence.jdbc.user”和“javax.persistence.jdbc.password”屬性以觸發為此 EntityManager 建立新的連線。請注意,此連線預設情況下僅用於寫入,讀取仍將使用共享連線池。要強制讀取也使用連線,應將“eclipselink.jdbc.exclusive-connection.mode”屬性設定為“Always”,但這取決於應用程式是否希望審計寫入或讀取。EclipseLink 還定義了一個“eclipselink.jdbc.exclusive-connection.is-lazy”屬性,用於配置連線是否應立即連線,或者僅在第一次需要時連線。如果只審計寫入,那麼延遲連線允許避免建立新資料庫連線的成本,除非發生寫入。
Map properties = new HashMap();
properties.put("javax.persistence.jdbc.user", user);
properties.put("javax.persistence.jdbc.password", password);
EntityManager em = factory.createEntityManager(properties);
如果使用 Java EE 和 DataSource,則資料庫使用者名稱和密碼可能能夠以相同的方式傳遞,具體取決於您的 JPA 提供商。
如果使用 JEE 和 JTA 管理的 EntityManager,則指定使用者/密碼可能更困難,因為 EntityManager 和 JDBC 連線不在應用程式的控制之下。永續性單元屬性仍然可能能夠在 EntityManager 上指定。只要在 EntityManager 建立資料庫連線之前完成此操作,它仍然會起作用。
在 JPA 2.0 中,可以使用 setProperty API
em.setProperty("javax.persistence.jdbc.user", user);
em.setProperty("javax.persistence.jdbc.password", password);
通常,每個使用者不會分配不同的安全許可權,而是定義一組分配了安全許可權的角色,並將使用者分配到角色中。如果為每個角色建立一個應用程式資料庫使用者,那麼您就可以擁有多個安全級別,但仍然允許連線池。
在 JPA 中啟用此功能的一種方法是為每個角色定義不同的連線池和永續性單元。這將允許連線池並處理基於角色的資料庫安全,但它在角色之間共享快取方面存在問題。
一些 JPA 提供商可能允許單個永續性單元定義多個連線池。
審計通常透過具有應用程式使用者和單個共享資料庫使用者來在應用程式中管理。這通常透過在所有已審計表中新增 AUDIT_USER 和 AUDIT_TIMESTAMP 列,以及在所有已審計物件中新增 auditUser 和 auditTimestamp 欄位來實現。當應用程式插入或更新物件時,它將設定這些欄位,並將它們儲存在資料庫中。JPA 事件也可以用於記錄審計資訊,或寫入單獨的審計表。
安全也由應用程式控制,允許使用者根據他們的應用程式使用者 ID 或角色訪問應用程式的不同部分。資料庫可用於儲存使用者登入資訊、角色和訪問許可權,但這些資訊僅位於普通表中,與資料庫使用者無關,並且資料庫不會強制執行其自身的安全性。
這種模型允許完全連線池,並使應用程式能夠控制審計和安全。
另請參閱:
- 歷史.
import javax.persistence.*;
@MappedSuperclass
public Class AuditedObject {
public static ThreadLocal currentUser = new ThreadLocal();
@Column("AUDIT_USER");
protected String auditUser;
@Column("AUDIT_TIMESTAMP");
protected Calendar auditTimestamp;
public String getAuditUser() {
return auditUser;
}
public void setAuditUser(String auditUser) {
this.auditUser = auditUser;
}
public Calendar getAuditTimestamp() {
return auditTimestamp;
}
public void setAuditTimestamp(Calendar auditTimestamp) {
this.auditTimestamp= auditTimestamp;
}
@PrePersist
@PreUpdate
public void updateAuditInfo() {
setAuditUser((String)AuditedObject.currentUser.get());
setAuditTimestamp(Calendar.getInstance());
}
}
某些資料庫(如 Oracle 資料庫)提供了一種機制,可以在現有資料庫連線上設定代理使用者。這允許使用共享連線池,但也為資料庫提供了一個使用者上下文。
一些 JPA 提供商支援代理身份驗證。
- EclipseLink/TopLink : 支援 Oracle 代理身份驗證。
某些資料庫(如 Oracle 資料庫)支援行級安全(虛擬專用資料庫)。典型的資料庫安全只允許按表分配訪問許可權。行級安全允許不同的使用者訪問每個表中的不同行。
一些 JPA 提供商支援行級安全和 VPD。
- EclipseLink/TopLink : 提供對 Oracle VPD 的支援。