《Spring Security 3》 精確的訪問控制

添加@PreAuthorize方法註解

我們第一個的設計決策就是要在業務層上添加方法安全,以保證用戶在修改密碼前已經作爲系統的合法用戶進行了登錄。這通過爲業務接口方法定義添加一個簡單的註解來實現,如下:

 

java代碼:
  1. public interface IUserService {    
  2.   @PreAuthorize("hasRole('ROLE_USER')")    
  3.   public void changePassword(String username, String password);    
  4. }   

 

這就是保證合法、已認證的用戶才能訪問修改密碼功能所要做的所有事情。Spring Security將會使用運行時的面向方面編程的切點(aspect oriented programming (AOP) pointcut)來對方法執行before advice,並在安全要求未滿足的情況下拋出AccessDeniedException異常。

 

讓Spring Security能夠使用方法註解

我們還需要在dogstore-security.xml中做一個一次性的修改,通過這個文件我們已經進行了Spring Security其他的配置。只需要在<http>聲明之前,添加下面的元素即可:

 

java代碼:
  1. <global-method-security pre-post-annotations="enabled"/>   

 

校驗方法安全

不相信如此簡單?那我們將ROLE_USER聲明修改爲ROLE_ADMIN。現在用用戶guest(密碼guest)登錄並嘗試修改密碼。你會在嘗試修改密碼時,看到如下的出錯界面:



如果查看Tomcat的控制檯,你可以看到很長的堆棧信息,開始是這樣的:

 

java代碼:
  1. DEBUG - Could not complete request    
  2. o.s.s.access.AccessDeniedException: Access is denied    
  3. at o.s.s.access.vote.AffirmativeBased.decide    
  4. at o.s.s.access.intercept.AbstractSecurityInterceptor.beforeInvocation    
  5. ...    
  6. at $Proxy12.changePassword(Unknown Source)    
  7. at com.packtpub.springsecurity.web.controller.AccountController.    
  8. submitChangePasswordPage    

 

基於訪問拒絕的頁面以及指向changePassword方法的堆棧信息,我們可以看到用戶被合理的拒絕對業務方法的訪問,因爲缺少ROLE_ADMIN的GrantedAuthority。你可以測試修改密碼功能對管理員用戶依舊是可以訪問的。

 

我們只是在接口上添加了簡單的聲明就能夠保證方法的安全,這是不是太令人興奮了?當然,我們不會願意Tomcat 原生的403錯誤頁面在我們的產品應用中出現——我們將會在第六章:高級配置與擴展講述訪問拒絕處理時,對其進行更新。

 

讓我們介紹一下實現方法安全的其它方式,然後進入功能的背後以瞭解其怎樣以及爲什麼能夠生效。

 

幾種實現方法安全的方式

除了@PreAuthorize註解以外,還有幾種其它的方式來聲明在方法調用前進行授權檢查的需求。我們會講解這些實現方法安全的不同方式,並比較它們在不同環境下的優勢與不足。

遵守JSR-250標準規則

JSR-250, Common Annotations for the Java Platform定義了一系列的註解,其中的一些是安全相關的,它們意圖在兼容JSR-250的環境中很方便地使用。Spring框架從Spring 2.x釋放版本開始就兼容JSR-250,包括Spring Security框架。

 

儘管JSR-250註解不像Spring原生的註解富有表現力,但是它們提供的註解能夠兼容不同的Java EE應用服務器實現如Glassfish,或面向服務的運行框架如Apache Tuscany。取決於你應用對輕便性的需求,你可能會覺得犧牲代碼的輕便性但減少對特定環境的要求是值得的。

 

要實現我們在第一個例子中的規則,我們需要作兩個修改,首先在dogstore-security.xml文件中:

 

java代碼:
  1. <global-method-security jsr250-annotations="enabled"/>    

 

其次,@PreAuthorize註解需要修改成@RolesAllowed註解。正如我們可能推斷出的那樣,@RolesAllowed註解並不支持SpEL表達式,所以它看起來很像我們在第二節中提到的URL授權。我們修改IuserService定義如下:

 

java代碼:
  1. @RolesAllowed("ROLE_USER")    
  2. public void changePassword(String username, String password);    

 

 

正如前面的練習那樣,如果不相信它能工作,嘗試修改ROLE_USER 爲ROLE_ADMIN並進行測試。

 

要注意的是,也可以提供一系列允許的GrantedAuthority名字,使用Java 5標準的字符串數組註解語法:

 

java代碼:
  1. @RolesAllowed({"ROLE_USER","ROLE_ADMIN"})    
  2. public void changePassword(String username, String password);    

 

 

JSR-250還有兩個其它的註解:@PermitAll 和@DenyAll。它們的功能正如你所預想的,允許和禁止對方法的任何請求。

 

【類層次的註解。注意方法級別的安全註解也可以使用到類級別上!如果提供了方法級別的註解,將會覆蓋類級別的註解。如果業務需要在整個類上有安全策略的話,這會非常有用。要注意的是使用這個功能要有良好的註釋的編碼規範,這樣開發人員能夠很清楚的瞭解類和方法的安全特性。】

 

我們將會在本章稍後的練習中介紹如何實現JSR-250風格的註解與Spring Security風格 的註解並存。

@Secured註解實現方法安全

Spring本身也提供一個簡單的註解,類似於JSR-250 的@RolesAllowed註解。@Secured註解在功能和語法上都與@RolesAllowed一致。唯一需要注意的不同點是要使用這些註解的話,要在<global-method-security>元素中明確使用另外一個屬性:

 

 

java代碼:
  1. <global-method-security secured-annotations="enabled"/>    

 

因爲@Secured與JSR標準的@RolesAllowed註解在功能上一致,所以並沒有充分的理由在新代碼中使用它,但是它能夠在Spring的遺留代碼中運行。

使用Aspect Oriented Programming (AOP)實現方法安全

實現方法安全的最後一項技術也可能是最強大的方法,它還有一個好處是不需要修改源代碼。作爲替代,它使用面向方面的編程方式爲一個方法或方法集合聲明切點(pointcut),而增強(advice)會在切點匹配的情況下進行基於角色的安全檢查。AOP的聲明只在Spring Security的XML配置文件中並不涉及任何的註解。

 

以下就是聲明保護所有的service接口只有管理權限才能訪問的例子:

 

 

java代碼:
  1. <global-method-security>    
  2.   <protect-pointcut access="ROLE_ADMIN"     
  3. expression="execution(* com.packtpub.springsecurity.service.I*Service.*(..))"/>    
  4. </global-method-security>    

 

切點表達式基於Spring AOP對AspectJ的支持。但是,Spring AspectJ AOP僅支持AspectJ切點表達式語言的一個很小子集——可以參考Spring AOP的文檔以瞭解其支持的表達式和其它關於Spring AOP編程的重要元素。

 

注意的是,可以指明一系列的切點聲明,以指向不同的角色和切點目標。以下的就是添加切點到DAO中一個方法的例子:

 

java代碼:
  1. <global-method-security>    
  2.   <protect-pointcut access="ROLE_USER"     
  3.           expression="execution(* com.packtpub.springsecurity.dao.IProductDao.getCategories(..)) &&  args()"/>    
  4.   <protect-pointcut access="ROLE_ADMIN" expression="execution(* com.packtpub.springsecurity.service.I*Service.*(..))"/>    
  5. </global-method-security>   


 

注意在新增的切點中,我們添加了一些AspectJ的高級語法,來聲明Boolean邏輯以及其它支持的切點,而參數可以用來確定參數的類型聲明。

 

同Spring Security其它允許一系列安全聲明的地方一樣,AOP風格的方法安全是按照從頂到底的順序進行的,所以需要按照最特殊到最不特殊的順序來寫切點。

 

使用AOP來進行編程即便是經驗豐富的開發人員可能也會感到迷惑。如果你確定要使用AOP來進行安全聲明,除了Spring AOP的參考手冊外,強烈建議你參考一些這個專題相關的書籍。AOP實現起來比較複雜,尤其是在解決不按照你預期運行的配置錯誤時更是如此。

比較方法授權的類型

以下的快速參考表可能在你選擇授權方法檢查時派上用場:

        

方法授權類型

聲明方式

JSR標準

允許SpEL表達式

@PreAuthorize

@PostAuthorize

註解

No

Yes

@RolesAllowed

@PermitAll

@DenyAll

註解

Yes

NO

@Secure

註解

No

No

protect-pointcut

XML

No

No

         大多數使用Java 5的Spring Security用戶傾向於使用JSR-250註解,以達到在IT組織間最大的兼容性和對業務類(以及相關約束)的重用。在需要的地方,這些基本的聲明能夠被Spring Security本身實現的註解所代替。

         如果你在不支持註解的環境中(Java 1.4或更早版本)中使用Spring Security,很不幸的是,關於方法安全的執行你的選擇可能會很有限。即使在這樣的情況下,對AOP的使用也提供了相當豐富的環境來開發基本的安全聲明。


原文 http://sishuok.com/forum/blogCategory/showByCategory.html?categories_id=77&user_id=2

發佈了38 篇原創文章 · 獲贊 1 · 訪問量 27萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章