1. 程式人生 > >Spring Security 入門詳解

Spring Security 入門詳解

Spring Security 入門詳解

 

1.Spring Security介紹

Spring Security是基於spring的應用程式提供宣告式安全保護的安全性框架,它提供了完整的安全性解決方案,能夠在web請求級別和方法呼叫級別
處理身份證驗證和授權.它充分使用了依賴注入和麵向切面的技術.

  Spring security主要是從兩個方面解決安全性問題:

  1. web請求級別:使用servlet過濾器保護web請求並限制URL級別的訪問
  2. 方法呼叫級別:使用Spring AOP保護方法呼叫,確保具有適當許可權的使用者採用訪問安全保護的方法.

2.Web請求級別的保護

  對於請求級別的安全性來說,主要時通過保護一個或多個URL,使得只有特定的使用者才能訪問,並其他使用者訪問該URL的內容.本文主要是基於spring mvc下整合Spring security模組.

2.1 宣告代理Servlet過濾器

  在web中的URL的一般需要過濾器進行保護,所以需要藉助一系列的Servlet過濾器提供各種各樣的安全性功能.這也需要在web.xml中配置一系列相關的<filter>,使得配置檔案臃腫難以閱讀.所以Spring security提供了代理Servelt過濾器可以解決該問題.如下面清單所示:

1 <filter>
2     <filter-name>springSecurityFilterChain</filter-name>
3     <filter-class>
4         org.springframework.web.filter.DelegatingFilterProxy
5     </filter-class>
6 </filter>

   DelegatingFilterProxy是一個代理的Servelt過濾器,它主要負責將工作委託給一個javax.servlet.Filter實現類,這個實現類作為一個<bean>已經註冊在Spring應用的上下文,且該bean的Id便是上面<filter-name>的名字,即springSecurityFilterChain.  

   springSecurityFilterChain,也可稱為FilterChainProxy.它可以連結任意多個其他的過濾器,根據這些過濾器提供不同的安全特性.但是你並不需要在spring配置檔案中配置該過濾器的bean和它所連結的其他過濾器

2.2 配置最小化web安全性和攔截請求

 1 <http auto-config="true">
 2     <intercept-url pattern="/admin/**" access="ROLE_ADMIN" />
 3 </http>

   在spring的配置檔案中加入這段程式碼可以攔截站點/admin分支行下的所有URL請求.並限制只有具備"ROLE_ADMIN"許可權的使用者才可以訪問,"ROLE_ADMIN"是自定義的一個許可權.pattern預設使用的是Ant格式。如果需要使用正則表示式則在http 元素的path-type設定為regex。<intercept-url>能夠攔截請求,主要是對指定的URL進行保護,如果使用者具有訪問指定的URL的許可權則通過否則拒絕。

  <http>元素將自動建立一個FilterChainProxy以及鏈中所有的過濾器bean.同時會將FilterChainProxy的bean託管給配置在web.xml的DelegatingFilterProxy.設定auto-config="true"會自動生成一個登陸介面,可以通過http://localhost:8080/你的專案名稱/spring_security_login.設定為ture也等價於下面的配置:

複製程式碼

<http>
    <form-login />
  <!--HTTP 基本認證 -->
    <http-basic/>
  <!-- 可以通過logout-url屬性設定使用者退出的url-->
    <logout />
    <intercept pattern="/**" access="ROLE_DEMO" />
</http>

複製程式碼

  Spring security 3.0以後加入了對SpEL的支援,可以將<http>元素的use-expressions設定為"true"便可使用SpEL。

<http auto-config="true" use-expressions="true">
   ..
    <intercept-url pattern="/admin/**" access="hasRole('ROLE_ADMIN')">
</http>

  Spring Security 支援的所有SpEL表示式如下:

安全表示式  計算結果
authentication   使用者認證物件
denyAll   結果始終為false
hasAnyRole(list of roles)   如果使用者被授權指定的任意許可權,結果為true
hasRole(role) 如果使用者被授予了指定的許可權,結果 為true
hasIpAddress(IP Adress) 使用者地址
isAnonymous()   是否為匿名使用者
isAuthenticated()   不是匿名使用者
isFullyAuthenticated   不是匿名也不是remember-me認證
isRemberMe()   remember-me認證
permitAll 始終true
principal 使用者主要資訊物件

2.3 通過表單安全登陸

   雖然<http>元素設定auto-config="true",可以自動生成一個自動登陸頁面。當一般開始都是採用自定義的登陸介面。所以需要進行下面配置:

<http auto-config="true">
    <!-- 設定登入頁配置 login-page指定了登入介面的檢視,authentication-failure-url則設定失敗後的重定向到相同的登陸介面-->
    <from-login login-processing-url="/static/j_spring_security_check"
    login-page="/login" 
    authentication-failure-url="/login?login_error=t">
</http>

  在自定義的登入介面中將表單提交地址設定為"/static/j_spring_security_check",同時需要將使用者名稱輸入框和密碼輸入框name分別設定為j_username和j_password 。有些應用中往往會設定記住密碼,方便使用者訪問應用,不需要每次都登入。實現該功能只需要在<http>元素中加入:

<!--key設定cookie的祕鑰的值,預設是SpringSecured。後一個屬性指定有效期  -->
<remember-me key="spitterKey" token-validity-seconds="2419200"/> 

  靜態頁面中加入:

<input  name="_spring_security_rember_me" type="checkbox"/>

2.4 強制請求使用https

  https傳輸資料比較安全,如將使用者,密碼提交可以使用https保證資料傳輸的安全。可以進行以下設定,保證每次對指定URL請求,Spring Security都會自動重定向為https請求。不管使用者訪問時是否加入https.

<intercept pattern="/admin/**" access="ROLE_DEMO" requires-channel="https" />

3. 保護檢視

  Spring Security提供jsp標籤庫,支援檢視級別的保護,這個標籤庫包含3個標籤:

  1. <security:accesscontrollist> :如果認證使用者具有許可權列表中的某一個許可權,那麼這個標籤範圍的內容將顯示。
  2. <security:authentication>: 訪問當前使用者認證物件的屬性。一般使用者顯示當前使用者的使用者名稱之類的。具有的使用者認證資訊有:
  • authorities:一組用於使用者所授予的GrantedAuthority物件
  • credentials:核實使用者的憑據
  • detail:認證的附加資訊(IP地址,會話ID等)
  • principal:使用者的主要資訊物件 

  3.<security:authorize>: 如果當前使用者滿足特定全新,則顯示標籤範圍的內容。例:

<!-- 顯示使用者資訊, 並將資訊複製給var變數,該變數的使用範圍為scope的範圍。var和scope可以不設定-->
 Hello <security:authentication property="principal.usrname" var="loginId" scope="request">
 <security:authorize access="hasRole('ROLE_ADMIN')">
    如果當前使用者有ROLE_ADMIN許可權,則顯示這部分內容
</security:authorize>

<security:authorize>除了使用access來指定許可權外還可以根據url設定具體許可權,即在攔截請求中指定的url的許可權。

<security:authorize url="/admin/**">
    如果當前使用者有/admin/**對應的許可權,則顯示這部分內容
</security:authorize>
4.認證使用者
 前面提到很多使用者物件和使用者許可權的問題,他們的關係和定義就是通過認證使用者來定義的。 Spring Security提供了以下認證策略:
  • 記憶體使用者儲存庫,即顯示的配置在spring配置檔案中。
  • 基於jdbc的使用者儲存庫
  • 基於LDAP的使用者儲存庫
  • OpenID 分散式使用者身份識別系統
  • 中心認證服務(CAS)
  • X.509證書
  • 基於JAAS的提供者

  這裡主要是介紹基於spirng配置和jdbc的。

4.1 配置記憶體使用者儲存庫

首先建立一個使用者服務,配置所有使用者和許可權資訊。然後交給認證管理器管理,認證管理器會將認證的任務交給一個或多個認證提供者。

複製程式碼

<!-- 使用者服務-->
<user-service id="userService">
    <user name="alibaba" password="123456" authorities="ROLE_ADMIN">
    <user name="baidu" password="66666" authorities="ROLE_BAIDU">
    ......
</user-service>
<!-- 認證管理器-->
<authentication-manager>
    <authentication-provider user-service-ref="userService"/>
</authentication-manager>

複製程式碼

  另一種方式將認證提供者和使用者服務裝配在一起,適用於只有一種使用者服務:  

複製程式碼

<!-- 認證提供者-->
<authentication-provider>
    <!-- 使用者服務-->
<user-service id="userService">
    <user name="alibaba" password="123456" authorities="ROLE_ADMIN">
    <user name="baidu" password="66666" authorities="ROLE_BAIDU">
    ......
</user-service>
</authentication-provider>

複製程式碼

4.2 基於資料庫進行認證

    這個是最常用的是使用者認證,因為很多應用都是採用資料庫儲存使用者資料。Spring Security提供了<jdbc-usr-service>.如果只指定了  data-source-ref得資料來源,那麼spring security會自己為我們寫sql語句從資料庫中查詢使用者和許可權資訊。但一般情況下,提供的查詢語句並不能和我們的資料庫對應上,所以我們需要自己寫sql語句。主要包括以下屬性:

  • users-by-username-query:根據使用者名稱查詢使用者名稱,密碼以及是否可用狀態
  • authorities-by-username-query:根據使用者名稱查詢使用者被使用者名稱和授權的許可權。
  • group-authorities-by-username-query:根據使用者名稱查詢使用者組的許可權。  
<jdbc-user-service id="userService"  data-source-ref="dataSource"
      users-by-username="select username,password, true from user where username=?"
      authories-by-username-query="select username,role from user_role where username=?" />  
<authentication-manager>
    <authentication-provider user-service-ref="userService"/>
</authentication-manager>

5.保護方法呼叫

  spring security的方法級別的保護是基於Spring AOP技術。首先需要在spring配置檔案中加以下配置,才能使spring Security保護那些使用相關注解的方法。

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

   spring Security支援4種方法級別安全性的方法:

  1. 使用@Secured註解方法,這是spring自帶的註解方法。@Secured("")內部的字串不具有SpEL特性,只能是具體的許可權。
  2. 使用@JSR-250 @RelosAllowed註解的方法。作用和使用方法與@Secured一樣,不同在於它不是spring框架的,所以可以做到和spring框架的解耦。
  3. 使用Spring 方法呼叫前和呼叫後註解方法。這些方法支援SpEL.
  4. 匹配一個或多個明確宣告的切點方法。

5.1 @Secured和 @RelosAllowed

複製程式碼

@Secured("ROLE_ADMIN")
public void addUser(User user){
    ...  
}
@RolesAllowed("ROLE_ADMIN")
public void updateUser(User user){
    ...  
}

複製程式碼

5.2 使用Spring 方法呼叫前和呼叫後註解方法

 可以使用SpEL方法有四種:

  1. @PreAuthorize: 在方法呼叫前,基於表示式計算結果來限制方法訪問
  2. @PostAuthorize: 允許方法呼叫,但是如果表示式結果為fasle則丟擲異常
  3. @PostFilter :允許方法呼叫,但必須按表示式過濾方法結果。
  4. @PreFilter:允許方法呼叫,但必須在進入方法前過濾輸入值

舉例清單

5.3 匹配一個或多個明確宣告的切點方法

    為多個方法設定相同的授權檢查,spring security提供了 <protect-pointcut>元素。配置如下:

<global-method-security secured-annotations="enabled" >
    <protect-pointcut access="ROLE_ADMIN" expression="execution(@com.securitytest.service.UserService**.*(String)"
</global-method-security>