Spring Security 入門詳解
Spring Security 入門詳解
1.Spring Security介紹
Spring Security是基於spring的應用程式提供宣告式安全保護的安全性框架,它提供了完整的安全性解決方案,能夠在web請求級別和方法呼叫級別 處理身份證驗證和授權.它充分使用了依賴注入和麵向切面的技術.
Spring security主要是從兩個方面解決安全性問題:
- web請求級別:使用servlet過濾器保護web請求並限制URL級別的訪問
- 方法呼叫級別:使用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個標籤:
- <security:accesscontrollist> :如果認證使用者具有許可權列表中的某一個許可權,那麼這個標籤範圍的內容將顯示。
- <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種方法級別安全性的方法:
- 使用@Secured註解方法,這是spring自帶的註解方法。@Secured("")內部的字串不具有SpEL特性,只能是具體的許可權。
- 使用@JSR-250 @RelosAllowed註解的方法。作用和使用方法與@Secured一樣,不同在於它不是spring框架的,所以可以做到和spring框架的解耦。
- 使用Spring 方法呼叫前和呼叫後註解方法。這些方法支援SpEL.
- 匹配一個或多個明確宣告的切點方法。
5.1 @Secured和 @RelosAllowed
@Secured("ROLE_ADMIN") public void addUser(User user){ ... } @RolesAllowed("ROLE_ADMIN") public void updateUser(User user){ ... }
5.2 使用Spring 方法呼叫前和呼叫後註解方法
可以使用SpEL方法有四種:
- @PreAuthorize: 在方法呼叫前,基於表示式計算結果來限制方法訪問
- @PostAuthorize: 允許方法呼叫,但是如果表示式結果為fasle則丟擲異常
- @PostFilter :允許方法呼叫,但必須按表示式過濾方法結果。
- @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>