歡迎您光臨本站 註冊首頁

Seam的安全框架——授權

←手機掃碼閱讀     火星人 @ 2014-03-09 , reply:0

Seam安全API為安全訪問組件、組件方法和頁面提供了幾種授權機制.本節將描述他們.一個需要注意的重要事項是如果你想使用任何高級特性(比如基於規則的許可權),你需要在components.xml中配置它們以得到支持.

1. 核心概念

Seam安全的建立是圍繞著用戶被賦予角色並且/或者許可權,允許它們執行那些在沒有必要的安全特權就不能執行的操作的前提下的.Seam安全API提供的每一種授權機制都建立在角色和許可權這些核心概念之上,這些概念擁有一個提供多種方式保護應用資源的易擴展的框架.

1.1. 什麼是角色?

角色是被賦予某些特權,可以執行一個和多個應用中的動作的用戶的一個 組 或 類別.簡單的角色僅僅由一個名稱組成(比如"admin","user","customer"等等).可以將角色賦予用戶(或者其他的角色),也可以被用來為方便分配指定的特權而創建用戶的邏輯組.

1.2. 什麼是許可權?

許可權是一種執行一個單獨的、特定的動作的特權(有時是一次性的).一個應用只使用許可權是完全可能的,然而角色在給一組用戶賦予許可權是提供了更高級別的便利 性.許可權的結構比角色稍複雜,主要由三個方面構成:目標、動作和接受者.許可權的目標是一個對象(或者一個任意名稱和類),允許指定的接受者(或用戶)執行 這個對象的一個特定的動作.例如,用戶「Bob」有許可權刪除customer對象.在這個例子中,許可權目標是「customer」,許可權動作是 「delete」,許可權的接受者是「Bob」.

本文中,許可權通常以target:action這種形式表現(忽略了接受者,儘管實際上一個接受者是必須的).

2. 保護組件

讓我們以@Restrict註釋來研究最簡單的授權和組件安全為開端.

@Restrict與類型安全的安全註釋

由於@Restrict註釋支持EL表達式,是的該註釋為保護組件方法提供強大並且靈活的方法,建議使用類型安全的等價物(以後描述),至少在編譯期間是安全的.

2.1. @Restrict註釋

使用@Restrict註釋,可以在方法和類級別上保護Seam組件.如果一個方法和它聲明類都使用了@Restrict註釋,方法的約束將有更高的優先順序(並且類約束將不起作用).如果一個方法調用在安全檢查使失敗,按照Identity.checkRestriction()的約定,它將拋出一個異常(參見內聯約束).在組件類級別上的@Restrict註釋等價於它每個方法都使用了這個註釋.

一個空的@Restrict意味著一個默認的許可權檢查:componentName:methodName.如下所示:

@Name("account")

public class AccountAction {

@Restrict public void delete() {

}

}

在這個例子中,調用delete()方法時需要的隱含許可權是account:delete.與@Restrict("#{s:hasPermission('account','delete')}")這樣寫是等價的.現在,讓我們看看另外一個例子:

@Restrict @Name("account")

public class AccountAction {

public void insert() {

}

@Restrict("#{s:hasRole('admin')}")

public void delete() {

}

}

這次,組件類本身使用了@Restrict註釋.這意味著任何沒有重寫@Restrict註釋的方法都需要一個隱含的許可權檢查.在這個例子中,insert()方法需要一個account:insert許可權,而delete()方法需要用戶是"admin"角色的一個成員.

在繼續深入前,先解釋一下上面看見的#{s:hasRole()}表達式.s:hasRole和s:hasPermission都是EL函數,貫穿整個安全API,這些函數能在任何EL表達式是使用.

通過一個EL表達式,@Restrict註釋的值可以引用存在於Seam上下文中的任何對象.這在為一個指定的對象實例執行許可權檢查是非常有用的.看這個例子:

@Name("account")

public class AccountAction {

@In Account selectedAccount;

@Restrict("#{s:hasPermission(selectedAccount,'modify')}")

public void modify() {

selectedAccount.modify();

}

}

在這個例子中需要說明的有趣的一點是hasPermission()函數調用了selectedAccount方法的引用.該變數值將在Seam上下文中查找,並傳遞給Identity的hasPermission()方法,在本例中它將確定用戶是否有必須的修改指定Account對象的許可權.

2.2. 內聯約束

有時它也可以在聲明在代碼中來執行安全檢查,而不使用@Restrict註釋.在這種情況下,簡單的使用Identity.checkRestriction()來評估安全表達式,就像這樣:

public void deleteCustomer() {

Identity.instance().checkRestriction("#{s:hasPermission(selectedCustomer,'delete')}");

}

如果這個指定表達式評估后不為true,並且

如果用戶沒有登錄,將拋出NotLoggedInException異常,或者

如果用戶已經登錄,將拋出AuthorizationException異常.

也可以在Java代碼中直接調用hasRole()和hasPermission()方法:

if (!Identity.instance().hasRole("admin"))

throw new AuthorizationException("Must be admin to perform this action");

if (!Identity.instance().hasPermission("customer", "create"))

throw new AuthorizationException("You may not create new customers");

3. 用戶界面中的安全

作為一個優良設計的用戶界面的指標之一就是用戶不會看見它沒有許可權使用的選項.基於以上的用戶的特權,使用非常一致的組件安全性EL表達式,Seam安全允許有條件的渲染 1)頁面的區段和 2)獨立的控制項.

讓我們看看一些界面安全的例子.,假設我們有一個登錄表單,它只能在用戶沒有登錄的時候被渲染.使用identity.isLoggedIn()特性,我們可以這樣寫:

<h:form class="loginForm" rendered="#{not identity.loggedIn}">

如果用戶沒有登錄,那麼登錄表單將被渲染-到目前為止,非常簡單.現在,假設頁面上有一個菜單,它包含一些只能被是「manager」角色的用戶訪問的動作.可以寫成這樣:

<h:outputLink action="#{reports.listManagerReports}" rendered="#{s:hasRole('manager')}">

Manager Reports

</h:outputLink>

這也相當直截了當.如果用戶不是manager角色的成員,那麼這個outputlink將不會被渲染.rendered屬性通常是控制項本身使用,或者是一個被包圍的<s:div>或<s:span>控制項.

現在看看一些更複雜的.假設你有一個h:dataTable控制項,其中的數據列表中你希望依靠用戶的許可權來決定是否被渲染而顯示.s:hasPermission這個EL函數允許我們傳遞一個可以決定是否用戶擁有要求的許可權的對象參數.這樣的被保護的dataTable可能像這樣:

<h:dataTable value="#{clients}" var="cl">

<h:column>

<f:facet name="header">Name</f:facet>

#{cl.name}

</h:column>

<h:column>

<f:facet name="header">City</f:facet>

#{cl.city}

</h:column>

<h:column>

<f:facet name="header">Action</f:facet>

<s:link value="Modify Client" action="#{clientAction.modify}"

rendered="#{s:hasPermission(cl,'modify')"/>

<s:link value="Delete Client" action="#{clientAction.delete}"

rendered="#{s:hasPermission(cl,'delete')"/>

</h:column>

</h:dataTable>

4. 保護頁面

頁面安全需要應用程序使用一個pages.xml文件,它也是非常容易配置的.僅僅是簡單在你需要保護的page元素之內包含一個<restrict/>元素即可.如果restrict元素沒有顯式的指定一個限制,那麼當通過non-faces(GET)請求訪問頁面時,將檢查隱含的許可權/viewId.xhtml:render,並且任何源於頁面的JSF postback(表單提交)都需要許可權/viewId.xhtml:restore.否則,指定的限制將被評定為一個標準的安全表達式,這裡有兩個例子:

<page view-id="/settings.xhtml">

<restrict/>

</page>

這個頁面對於non-faces請求隱含一個許可權許可:/settings.xhtml:render,對於faces請求隱含一個許可權許可:/settings.xhtml:restore.

<page view-id="/reports.xhtml">

<restrict>#{s:hasRole('admin')}</restrict>

</page>

訪問這個頁面的faces和non-faces請求都需要用戶是admin角色的成員之一.

5. 保護實體

Seam安全也是的為實體的讀取,插入,更新和刪除動作應用安全限制成為可能.

為了保護實體類的所有的動作,需要在類本身添加一個@Restrict註釋:

@Entity

@Name("customer")

@Restrict

public class Customer {

}

如果在@Restrict註釋中沒有指定表達式,那麼執行的默認的安全檢查是entity:action的許可權檢查,這個許可權目標是實體實例,並且這個action是讀取(read), 插入(insert), 更新(update)或者刪除(delete).

也可能通過把@Restrict註解放在相關的實體生命周期的方法上(註解如下所述),而只限制某些動作:

@PostLoad - 在實體實例從資料庫中載入之後調用.用這個方法配置一個 read 許可.

@PrePersist - 在插入實體的一個新實例之前調用.用這個方法配置一個 insert 許可.

@PreUpdate - 在實體更新之前調用.用這個方法配置一個 update 許可.

@PreRemove - 在實體刪除之前調用.用這個方法配置一個 delete 許可.

這裡有一個例子,說明實體方法如何配置成給任何 insert 操作執行安全檢查. 請注意這個方法不需要做任何事情,有關安全的唯一重要的是它如何被註解:

@PrePersist @Restrict

public void prePersist() {}

使用 /META-INF/orm.xml

你也可以在/META-INF/orm.xml中指定一個回調方法:

<?xml version="1.0" encoding="UTF-8"?>

<entity-mappings xmlns="http://java.sun.com/xml/ns/persistence/orm"

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xsi:schemaLocation="http://java.sun.com/xml/ns/persistence/orm http://java.sun.com/xml/ns/persistence/orm_1_0.xsd"

version="1.0">

<entity class="Customer">

<pre-persist method-name="prePersist" />

</entity>

</entity-mappings>

當然,你任然需要在有@Restrict的Customer中註釋prePersist()方法.

這裡有一個檢查已驗證用戶是否允許插入一個新的MemberBlog記錄(來自seamspace例子)的實體許可權規則的例子.這個被安全檢查的實體自動插入到工作內存中(本例中是MemberBlog):

rule InsertMemberBlog

no-loop

activation-group "permissions"

when

principal: Principal()

memberBlog: MemberBlog(member : member -> (member.getUsername().equals(principal.getName())))

check: PermissionCheck(target == memberBlog, action == "insert", granted == false)

then

check.grant();

end;

如果當前已驗證用戶(由Principal指明)和創建blog條目的成員有相同的用戶名,那麼這個規則將賦予其許可權memberBlog:insert.可以在示例代碼中看到"principal: Principal()"結構是一個綁定的變數,它綁定了來自工作內存的Principal對象的實例,並且分配這個變數名稱為principal.變數綁定允許它的值在其他地方可以引用到,比如接下來的一行中比較成員的用戶名和Principal的名字.更多詳細情況,請參考JBoss Rules文檔.

,我們需要安裝一個JianTingQi,以集成Seam安全和你的JPA提供者.

5.1. 使用JPA的實體安全

使用一個EntityListener來進行EJB3實體Bean的安全檢查.你可以使用下面的META-INF/orm.xml文件安裝這個JianTingQi:

<?xml version="1.0" encoding="UTF-8"?>

<entity-mappings xmlns="http://java.sun.com/xml/ns/persistence/orm"

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xsi:schemaLocation="http://java.sun.com/xml/ns/persistence/orm http://java.sun.com/xml/ns/persistence/orm_1_0.xsd"

version="1.0">

<persistence-unit-metadata>

<persistence-unit-defaults>

<entity-listeners>

<entity-listener class="org.jboss.seam.security.EntitySecurityListener"/>

</entity-listeners>

</persistence-unit-defaults>

</persistence-unit-metadata>

</entity-mappings>

5.2. 使用一個可管理的Hibernate回話的實體安全

如果你使用一個通過Seam配置的Hibernate的SessionFactory,並且使用了註釋,或者orm.xml文件,那麼你不需要做任何其他特別的操作就可以使用實體安全.

6. 類型安全的許可權註釋

Seam提供了一些可以作為@Restrict的替換的註釋,這些註釋提供在編譯時是安全的好處,它們不像@Restrict那樣支持任意的EL表達式.

開箱即用,Seam有著標準的基於CRUD許可權的註釋,添加你自己的註釋也只是一個簡單的問題.接下來的這些註釋是org.jboss.seam.annotations.security包提供的:

@Insert

@Read

@Update

@Delete

要使用這些註釋,你只需簡單的把它們放在你希望執行安全檢查的方法和參數那裡.如果放在方法上,那麼它們應該指定一個將檢查許可權的目標類.如下述例子:

@Insert(Customer.class)

public void createCustomer() {

}

在這個例子中,許可權檢查將被執行以確保用戶有創建一個新的Customer對象的權利.許可權檢查的目標是Customer.class(實際是java.lang.Class實例本身),並且動作是註釋名稱的小寫值,本例中是insert.

也可以相同的方式對組件方法的參數進行註釋.如果這樣註釋了,那麼它不須要指定一個許可權目標(參數值本身就是許可權檢查的目標):

public void updateCustomer(@Update Customer customer) {

}

為了創建你自己的安全註釋,你只要簡單的使用@PermissionCheck註釋,例如:

@Target({METHOD, PARAMETER})

@Documented

@Retention(RUNTIME)

@Inherited

@PermissionCheck

public @interface Promote {

Class value() default void.class;

}

如果你希望使用其他值來重載默認的許可權動作名稱(小寫的註釋名稱),你應該在@PermissionCheck註釋中指定:

@PermissionCheck("upgrade")

7. 類型安全的角色註釋

除了支持類型安全的許可權註釋,Seam安全也提供類型安全的角色註釋,這些註釋允許你基於當前以驗證用戶的角色關係來限制訪問組件方法.Seam提供開箱即用的這樣一個註釋,org.jboss.seam.annotations.security.Admin,它用來限制必須是admin成員之一的用戶才能訪問一個方法.為了創建你自己的角色註釋,簡單的使用org.jboss.seam.annotations.security.RoleCheck元註釋,像下面的例子那樣:

@Target({METHOD})

@Documented

@Retention(RUNTIME)

@Inherited

@RoleCheck

public @interface User {

}

任何使用了上述例子中的@User註釋的方法將被自動攔截並且檢查用戶是否是相應的角色名稱的關係(小寫的註釋名,本例中是user).


[火星人 ] Seam的安全框架——授權已經有521次圍觀

http://coctec.com/docs/java/show-post-60966.html