Spring Security 保護業務層

保護業務層前端

Spring Security支持添加受權層(或者基於受權的數據處理)到應用中全部Spring管理的bean中。儘管不少的開發人員關注層的安全,其實業務層的安全同等重要,由於惡意的用戶可能會穿透web層,可以經過沒有UI的前端訪問暴露的服務,如使用webservice。java

讓咱們查看下面的圖以瞭解咱們將要添加安全層的位置:web

Spring Security有兩個主要技術以實現方法的安全:spring

  • 事先受權(Pre-authorization)保證在執行一個方法以前須要知足特定的要求——例如,一個用戶要擁有特定的GrantedAuthority,如ROLE_ADMIN。不能知足聲明的條件將會致使方法調用失敗;express

  • 過後受權(Post-authorization)保證在方法返回時,調用的安全實體知足聲明的條件。這不多被使用,可是可以在一些複雜交互的業務方法周圍提供額外的安全層。        編程

       事先和過後受權在面向對象設計中提供了所謂的前置條件和後置條件(preconditions and ostconditions)。前置條件和後置條件容許開發者聲明運行時的檢查,從而保證在一個方法執行時特定的條件須要知足。在安全的事前受權和過後受權中,業務層的開發人員須要對特定的方法肯定明確的安全信息,並在接口或類的API聲明中添加指望的運行時條件。正如你可能想象的那樣,這須要大量的規劃以免沒必要要的影響。數組

保護業務層方法的基本知識

         讓咱們以JBCP Pets中業務層的幾個方法爲例闡述怎樣爲它們應用典型的規則。安全

         咱們對JBCP Pets的基礎代碼進行了從新組織以實現三層的設計,做爲修改的一部分咱們抽象出了前面章節已經介紹到的修改密碼功能到業務層。不一樣於用web MVC的控制器直接訪問JDBC DAO,咱們選擇插入一個業務服務以提供要求的附加功能。下圖對此進行了描述:服務器

咱們可以看到在例子中com.packtpub.springsecurity.service.IuserService接口表明了應用架構的業務層,而這對咱們來講,是一個合適位置來添加方法級的安全。架構

添加@PreAuthorize方法註解

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

public interface IUserService {  
  @PreAuthorize("hasRole('ROLE_USER')")  
  public void changePassword(String username, String password);  
}

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

讓Spring Security可以使用方法註解

         咱們還須要在dogstore-security.xml中作一個一次性的修改,經過這個文件咱們已經進行了Spring Security其餘的配置。只須要在<http>聲明以前,添加下面的元素便可:

<global-method-security pre-post-annotations="enabled"/>

校驗方法安全

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

校驗方法安全

         不相信如此簡單?那咱們將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。你能夠測試修改密碼功能對管理員用戶依舊是能夠訪問的。

         咱們只是在接口上添加了簡單的聲明就可以保證方法的安全,這是否是太使人興奮了?

         讓咱們介紹一下實現方法安全的其它方式,而後進入功能的背後以瞭解其怎樣以及爲何可以生效。

幾種實現方法安全的方式

         除了@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。取決於你應用對輕便性的需求,你可能會以爲犧牲代碼的輕便性但減小對特定環境的要求是值得的。

         要實現咱們在第一個例子中的規則,咱們須要做兩個修改,首先在

<global-method-security jsr250-annotations="enabled"/>  

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

@RolesAllowed("ROLE_USER")  

public void changePassword(String username, String password); 

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

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

@RolesAllowed({"ROLE_USER","ROLE_ADMIN"})  

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>元素中明確使用另一個屬性:

<global-method-security secured-annotations="enabled"/>

由於@Secured與JSR標準的@RolesAllowed註解在功能上一致,因此並無充分的理由在新代碼中使用它,可是它可以在Spring的遺留代碼中運行。

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

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

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

<global-method-security>  

  <protect-pointcut access="ROLE_ADMIN"   

expression="execution(* com.packtpub.springsecurity.service.I*Service.*(..))"/>  

</global-method-security>  

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

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

<global-method-security>  

  <protect-pointcut access="ROLE_USER"   

expression="execution(* com.packtpub.springsecurity.dao.IProductDao.getCategories(..)) &&  args()"/>  

  <protect-pointcut access="ROLE_ADMIN" expression="execution(* com.packtpub.springsecurity.service.I*Service.*(..))"/>  

</global-method-security>  

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

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

         使用AOP來進行編程即使是經驗豐富的開發人員可能也會感到迷惑。

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

相關文章
相關標籤/搜索