spring安全框架系列springSecurity

使用一個新的框架之前,首先我們來認識一下springSecurity,畢竟框架這種東西有時靠不住,所以學到他的思想纔是最重要的,很多人都知道這麼用,具體爲什麼,沒有人告訴我們,首先我們從最基本的看起,瞭解一些入門知識是有必要的:
1.4.1.1. Core -spring-security-core.jar
包含了核心認證和權限控制類和接口, 運程支持和基本供應 API。使用 spring Security
所必須的。支持單獨運行的應用, 遠程客戶端,方法(服務層)安全和 JDBC 用戶供應。
包含頂級包:
org.springframework.security.core
org.springframework.security.access
org.springframework.security.authentication
org.springframework.security.provisioning
org.springframework.security.remoting

1.4.1.2. Web -spring-security-web.jar
包含過濾器和對應的 web 安全架構代碼。任何需要依賴 servlet API 的。 你將需要它,如
果 你 需 要 Spring Security Web 認 證 服 務 和 基 於 URL 的 權 限 控 制 。 主 包 是
org.springframework.security.web。

1.4.1.3. Config -spring-security-config.jar
包含安全命名控制解析代碼(因此我們不能直接把它用在你的應用中)。你需要它, 如果使用了SpringSecurityXML命名控制來進行配置。主包是
org.springframework.security.config。

1.4.1.4. LDAP -spring-security-ldap.jar
LDAP 認證和實現代碼,如果你需要使用 LDAP 認證或管理 LDAP 用戶實體就是必須的。頂
級包是org.springframework.security.ldap。

1.4.1.5. ACL -spring-security-acl.jar
處理領域對象 ACL 實現。用來提供安全給特定的領域對象實例,在你的應用中。 頂級包是
org.springframework.security.acls。

1.4.1.6. CAS -spring-security-cas-client.jar
Spring Security 的 CAs 客戶端集成。如果你希望使用 Spring Security web 認證 整合
一個 CAS 單點登錄服務器。頂級包是 org.springframework.security.cas。

1.4.1.7. OpenID -spring-security-openid.jar
OpenID web 認 證 支 持 。 用 來 認 證 用 戶 , 通 過 一 個 外 部 的 OpenID 服 務 。
org.springframework.security.openid。需要 OpenID4Java。

在許多例子裏,你會看到(在示例中)應用,我們通常使用”security”作爲默認的命名空間,
而不是”beans”,這意味着我們可以省略所有 security 命名空間元素的前綴,使上下文更
容易閱讀。 如果你把應用上下文分割成單獨的文件,讓你的安全配置都放到其中一個文件
裏,這樣更容易使用這種配置方法。 你的安全應用上下文應該像這樣開頭:

<beans:beans xmlns="http://www.springframework.org/schema/security"  
xmlns:beans="http://www.springframework.org/schema/beans"  
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
xsi:schemaLocation="http://www.springframework.org/schema/beans  
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd  
http://www.springframework.org/schema/security  
http://www.springframework.org/schema/security/spring-security-3.0.xsd">  
...  
</beans:beans>  

2.1.1. 命名空間的設計
命名空間被用來設計成,處理框架內最常見的功能,提供一個簡化和簡潔的語法,使他們在
一個應用程序裏。 這種設計是基於框架內的大型依賴,可以分割成下面這些部分:
Web/HTTP 安全 - 最複雜的部分。設置過濾器和相關的服務 bean 來應用框架驗證機制,
保護 URL,渲染登錄和錯誤頁面還有更多。
業務類(方法)安全 - 可選的安全服務層。
AuthenticationManager - 通過框架的其它部分,處理認證請求。
AccessDecisionManager - 提供訪問的決定,適用於 web 以及方法的安全。一個默認的
主體會被註冊,但是你也可以選擇自定義一個,使用正常的 spring bean 語法進行聲明。
AuthenticationProviders - 驗證管理器驗證用戶的機制。 該命名空間提供幾種標準選
項,意味着使用傳統語法添加自定義 bean。
UserDetailsService - 密切相關的認證供應器,但往往也需要由其他 bean 需要。

2.2.1. 配置 web.xml
我們要做的第一件事是把下面的 filter 聲明添加到 web.xml 文件中:

<filter>  
<filter-name>springSecurityFilterChain</filter-name>  
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>  
</filter>  
<filter-mapping>  
<filter-name>springSecurityFilterChain</filter-name>  
<url-pattern>/*</url-pattern>  
</filter-mapping>  

這是爲 Spring Security 的 web 機制提供了一個調用鉤子。 DelegatingFilterProxy 是一個 SpringFramework 的類,它可以代理一個 applicationcontext 中定義的 Springbean 所實現的 filter。 這種情況下,bean 的名字是”springSecurityFilterChain”,這是由命名空間創建的用於處理 web 安全的一個內部的機制。 注意,你不應該自己使用這個bean 的 名 字 。 一 旦 你 把 這 個 添 加 到 你 的 web.xml 中 , 你 就 準 備 好 開 始 編 輯 呢 applicationcontext 文件了。 web 安全服務是使用元素配置的。
2.2.2. 最小 配置
只需要進行如下配置就可以實現安全配置:
[html] view plain copy print?

<authentication-manager>  
<authentication-provider>  
<user-service>  
<user name="jimi" password="jimispassword" authorities="ROLE_USER,ROLE_ADMIN" />  
<usernameusername="bob" password="bobspassword" authorities="ROLE_USER" />  
</user-service>  
</authentication-provider>  
</authentication-manager>  

這些過濾器的位置都是預定義好的。
元 素 創 建 了 一 個 DaoAuthenticationProvider bean ,
元素創建了一個 InMemoryDaoImpl。 所有 authentication-provider元 素 必 須 作 爲 的 子 元 素 ,它 創 建 了 一 個ProviderManager,並把 authentication provider 註冊到它裏面。 你可以在命名空間附錄中找到關於創建這個 bean 的更新信息。很值得去交叉檢查一下這裏,如果你希望開始理解框架中哪些是重要的類 以及它們是如何使用的,特別是如果你希望以後做一些自定義工作。
上面的配置定義了兩個用戶,他們在應用程序中的密碼和角色(用在權限控制上)。 也可以從一個標準 properties 文件中讀取這些信息,使用 user-service 的 properties 屬性。 參考 in-memoryauthentication 獲得更多信息。 使用元素意味着 用 戶 信 息 將 被 認 證 管 理 用 作 處 理 認 證 請 求 。你 可 以 擁 有 多 個元素來定義不同的認證數據, 每個會被需要時使用。
現在,你可以啓動程序,然後就會進入登錄流程了。 試試這個,或者試試工程裏的“tutorial”
例子. 上述配置實際上把很多服務添加到了程序裏,因爲我們使用了 auto-config 屬性。
比如,表單登錄和”remember-me”服務自動啓動了。
2.2.2.1. auto-config 包含了什麼?
我們在上面用到的 auto-config 屬性,其實是下面這些配置的縮寫:

<http>  
<form-login />  
<http-basic />  
<logout />  
</http>  

這些元素分別與 form-login,基本認證和註銷處理對應。
他們擁有各自的屬性,來改
變他們的具體行爲。
2.2.2.2. 表單和基本登錄選項
你也許想知道,在需要登錄的時候,去哪裏找這個登錄頁面,到現在爲止我們都沒有提到任
何的 HTML 或 JSP 文件。 實際上,如果我們沒有確切的指定一個頁面用來登錄, Spring
Security 會自動生成一個,基於可用的功能,爲這個 URL 使用標準的數據,處理提交的登
錄,然後在登陸後發送到默認的目標 URL。 然而,命名空間提供了許多支持,讓你可以自
定義這些選項。 比如,如果你想實現自己的登錄頁面,你可以使用:

<http auto-config='true'>  
<intercept-urlpatternintercept-urlpattern="/login.jsp*"access="IS_AUTHENTICATED_ANONYMOUSLY"/>  
<intercept-urlpatternintercept-urlpattern="/**" access="ROLE_USER" />  
<form-loginlogin-pageform-loginlogin-page='/login.jsp'/>  
</http> 

注意,你依舊可以使用 auto-config。 這個 form-login 元素會覆蓋默認的設置。 也要注
意我們需要添加額外的 intercept-url 元素,指定用來做登錄的頁面的 URL, 這些 URL 應
該可以被匿名訪問。[4] 否則,這些請求會被/**部分攔截,它沒法訪問到登錄頁面。 這是
一個很常見的配置錯誤,它會導致系統出現無限循環。 Spring Security 會在日誌中發出
一個警告,如果你的登錄頁面是被保護的。 也可能讓所有的請求都匹配特定的模式,通過
完全的安全過濾器鏈:

<http auto-config='true'>  
<intercept-urlpatternintercept-urlpattern="/css/**" filters="none"/>  
<intercept-urlpatternintercept-urlpattern="/login.jsp*" filters="none"/>  
<intercept-urlpatternintercept-urlpattern="/**" access="ROLE_USER" />  
<form-login login-page='/login.jsp'/>  
</http>  

主要的是意識到這些請求會被完全忽略,對任何 Spring Security 中 web 相關的配置,或
額外的屬性,比如requires-channel, 所以你會不能訪問當前用戶信息,或調用被保護
方法,在請求過程中。 使用access=’IS_AUTHENTICATED_ANONYMOUSLY’作爲一個
選擇方式 如果你還想要安全過濾器鏈起作用。
如果你希望使用基本認證,代替表單登錄,可以把配置改爲:

<http auto-config='true'>  
<intercept-urlpatternintercept-urlpattern="/css/**" filters="none"/>  
<intercept-urlpatternintercept-urlpattern="/login.jsp*" filters="none"/>  
<intercept-urlpatternintercept-urlpattern="/**" access="ROLE_USER" />  
<form-login login-page='/login.jsp'/>  
</http>  

基本身份認證會被優先用到,在用戶嘗試訪問一個受保護的資源時,用來提示用戶登錄。 在
這種配置中,表單登錄依然是可用的,如果你還想用的話,比如,把一個登錄表單內嵌到其
他頁面裏。
2.2.2.2.1. 設置一個默認的提交登陸目標
如果在進行表單登陸之前,沒有試圖去訪問一個被保護的資源,default-target-url 就會起作用。
這 是 用 戶 登 陸 後 會 跳 轉 到 的 URL , 默 認 是 “/” 。你也可以把always-use-default-target 屬性配置成”true”,這樣用戶就會一直跳轉到這一頁(無論登陸是“跳轉過來的”還是用戶特定進行登陸)。 如果你的系統一直需要用戶從首頁進入,就可以使用它了,比如:

<http>  
<intercept-urlpatternintercept-urlpattern='/login.htm*' filters='none'/>  
<intercept-urlpatternintercept-urlpattern='/**' access='ROLE_USER' />  
<form-loginlogin-pageform-loginlogin-page='/login.htm' default-target-url='/home.htm'  
always-use-default-target='true'/>  
</http>  

2.2.3. 使用其他認證提供器
現實中,你會需要更大型的用戶信息源,而不是寫在 application context 裏的幾個名字。多數情況下,你會想把用戶信息保存到數據庫或者是 LDAP 服務器裏。 LDAP 命名空間會在 LDAP 章裏詳細討論,所以我們這裏不會講它。 如果你自定義了一個 Spring Security的UserDetailsService實現,在你applicationcontext中 名 叫”myUserDetailsService”,然後你可以使用下面的驗證。

<authentication-manager>  
<authentication-provideruser-service-refauthentication-provideruser-service-ref='myUserDetailsService'/>  
</authentication-manager>  

如果你想用數據庫,可以使用下面的方式

<authentication-manager>  
<authentication-provider>  
<jdbc-user-servicedata-source-refjdbc-user-servicedata-source-ref="securityDataSource"/>  
</authentication-provider>  
</authentication-manager>  

這裏的“securityDataSource”就是 DataSource bean 在 application context 裏的名
字,它指向了包含着 Spring Security 用戶信息的表。 另外,你可以配置一個 Spring
SecurityJdbcDaoImpl bean,使用user-service-ref 屬性指定:

<authentication-manager>  
<authentication-provideruser-service-refauthentication-provideruser-service-ref='myUserDetailsService'/>  
</authentication-manager>  
<beans:beanidbeans:beanid="myUserDetailsService"  
class="org.springframework.security.core.userdetails.jdbc.JdbcDaoImpl">  
<beans:propertynamebeans:propertyname="dataSource" ref="dataSource"/>  
</beans:bean>  

你也可以使用標準的AuthenticationProvider 類,像下面

<authentication-manager>  
<authentication-providerrefauthentication-providerref='myAuthenticationProvider'/>  
</authentication-manager>  

這裏myAuthenticationProvider 是你的 applicationcontext 中的一個 bean 的名字,
它實現了AuthenticationProvider。 查看 Section 2.6, “驗證管理器和命名空間 ”瞭解更多信
息,AuthenticationManager 使用命名空間在 Spring Security 中是如何配置的。
2.2.3.1. 添加一個密碼編碼器
你的密碼數據通常要使用一種散列算法進行編碼。 使用元素支持
這個功能。 使用 SHA 加密密碼,原始的認證供應器配置,看起來就像這樣:

<authentication-manager>  
<authentication-provider>  
<password-encoderhashpassword-encoderhash="sha"/>  
<user-service>  
<usernameusername="jimi"password="d7e6351eaa13189a5a3641bab846c8e8c69ba39f"  
authorities="ROLE_USER,ROLE_ADMIN" />  
<usernameusername="bob" password="4e7421b1b8765d8f9406d87e7cc6aa784c4ab97f"  
authorities="ROLE_USER"/>  
</user-service>  
</authentication-provider>  
</authentication-manager>  

在使用散列密碼時,用鹽值防止字典攻擊是個好主意,Spring Security 也支持這個功能。
理想情況下,你可能想爲每個用戶隨機生成一個鹽值,不過,你可以使用 從
UserDetailsService 讀取出來的 UserDetails 對象中的屬性。 比如,使用 username 屬
性,你可以這樣用:

<password-encoderhashpassword-encoderhash="sha">  
<salt-sourceuser-propertysalt-sourceuser-property="username"/>  
</password-encoder>  

你可以通過password-encoder 的 ref 屬性,指定一個自定義的密碼編碼器 bean。 這應
該 包 含 applicationcontext 中 一 個 bean 的 名 字 , 它 應 該 是 Spring Security 的
PasswordEncoder 接口的一個實例。

2.3. 高級 web 特性
2.3.1. Remember-Me 認證
參考 Remember-Me 章獲得 remember-me 命名空間配置的詳細信息。
2.3.2. 添加 HTTP/HTTPS 信道安全
如果你的同時支持 HTTP 和 HTTPS 協議,然後你要求特定的 URL 只能使用 HTTPS,這時
可以直接使用的requires-channel 屬性:

<http>  
<intercept-urlpatternintercept-urlpattern="/secure/**" access="ROLE_USER"requires-channel="https"/>  
<intercept-urlpatternintercept-urlpattern="/**" access="ROLE_USER" requires-channel="any"/>  
...  
</http>  

使用了這個配置以後,如果用戶通過 HTTP 嘗試訪問”/secure/**”匹配的網址,他們會先
被重定向到 HTTPS 網址下。 可用的選項有”http”,”https” 或 “any”。 使用”any”意味
着使用 HTTP 或 HTTPS 都可以。
如果你的程序使用的不是 HTTP 或 HTTPS 的標準端口,你可以用下面的方式指定端口對應
關係:

<http>  
...  
<port-mappings>  
<port-mappinghttpport-mappinghttp="9080" https="9443"/>  
</port-mappings>  
</http>  

2.3.3. 會話管理
2.3.3.1. 檢測超時
你可以配置 Spring Security 檢測失效的 session ID, 並把用戶轉發到對應的 URL。這
可 以通 過session-management 元 素配 置:

<http>  
...  
<session-management invalid-session-url="/sessionTimeout.htm"/>  
</http>  

2.3.3.2. 同步會話控制
如果你希望限制單個用戶只能登錄到你的程序一次,Spring Security 通過添加下面簡單的
部分支持這個功能。首先,你需要把下面的監聽器添加到你的 web.xml 文件裏,讓 Spring

Security 獲 得 session 生 存 周 期 事 件 :

<listener>  
<listener-class>  
org.springframework.security.web.session.HttpSessionEventPublisher  
</listener-class>  
</listener>   

然後,在你的 applicationcontext 加入如下部分:

<http>  
...  
<session-management>  
<concurrency-controlmax-sessionsconcurrency-controlmax-sessions="1" />  
</session-management>  
</http>  

這將防止一個用戶重複登錄好幾次-第二次登錄會讓第一次登錄失效。通常我們更想防止第
二次登錄,這時候我們可以使用

<http>  
...  
<session-management>  
<concurrency-controlmax-sessionsconcurrency-controlmax-sessions="1" error-if-maximum-exceeded="true" />  
</session-management>  
</http>  

第二次登錄將被阻止,通過 “ 注入 ” ,我們的意思是用戶會被轉發到
authentication-failure-url,如果使用了 form-based 登錄。 如果第二次驗證使用了其
他非內置的機制,比如“remember-me”,一個“未認證”(402)錯誤就會發送給客戶端。如
果 你 希 望 使 用 一 個 錯 誤 頁 面 替 代 , 你 可 以 在session-management 中 添 加
session-authentication-error-url 屬性。
如果你爲 form-based 登錄使用了自定義認證, 你就必須特別配置同步會話控制。更多的
細節可以在 會話管理章節找到。
2.3.3.3. 防止 Session 固定攻擊
Session 固定攻擊是一個潛在危險,當一個惡意攻擊者可以創建一個 session 訪問一個網站
的時候,然後說服另一個用戶登錄到同一個會話上(比如,發送給他們一個包含了 session
標識參數的鏈接)。 Spring Security 通過在用戶登錄時,創建一個新 session 來防止這
個問題。 如果你不需要保護,或者它與其他一些需求衝突,你可以通過使用 中的
session-fixation-protection 屬性來配置它的行爲,它有三個選項
migrateSession - 創建一個新 session,把原來 session 中所有屬性複製到新 session
中。這是默認值。
none - 什麼也不做,繼續使用原來的 session。
newSession - 創建一個新的“乾淨的”session,不會複製 session 中的數據。
2.4.1.1. 使用protect-pointcut 添加安全切點
protect-pointcut 是非常強大的,它讓你可以用簡單的聲明對多個 bean 的進行安全聲明。
參考下面的例子:

<global-method-security>  
<protect-pointcutexpressionprotect-pointcutexpression="execution(* com.mycompany.*Service.*(..))"  
access="ROLE_USER"/>  
</global-method-security>

這樣會保護 applicationcontext 中的符合條件的 bean 的所有方法,這些 bean 要在
com.mycompany 包下,類名以”Service”結尾。 ROLE_USER 的角色才能調用這些方
法。 就像 URL 匹配一樣,指定的匹配要放在切點隊列的最前面,第一個匹配的表達式纔會
被用到。
2.5. 默認的AccessDecisionManager

這章假設你有一些 Spring Security 權限控制有關的架構知識。 如果沒有,你可以跳過這
段,以後再來看,因爲這章只是爲了自定義的用戶設置的,需要在簡單基於角色安全的基礎
上加一些客戶化的東西。
當你使用命名空間配置時,默認的 AccessDecisionManager 實例會自動註冊,然後用來
爲 方 法 調 用 和 web URL 訪 問 做 驗 證 , 這 些 都 是 基 於 你 設 置 的 intercept-url 和
protect-pointcut 權限屬性內容(和註解中的內容,如果你使用註解控制方法的權限)。
默認的策略是使用一個 AffirmativeBased AccessDecisionManager ,以及 RoleVoter
和AuthenticatedVoter。 可以在 authorization 中獲得更多信息。
2.5.1. 自定義AccessDecisionManager
如果你需要使用一個更復雜的訪問控制策略,把它設置給方法和 web 安全是很簡單的。
對於方法安全,你可以設置 global-security 裏的access-decision-manager-ref 屬性,
用對應AccessDecisionManager bean 在 applicationcontext 裏的 id:

<global-method-securityaccess-decision-manager-refglobal-method-securityaccess-decision-manager-ref="myAccessDecisionManagerBean">  
...  
</global-method-security>  

web 安全安全的語法也是一樣,但是放在 http 元素裏:

<httpaccess-decision-manager-refhttpaccess-decision-manager-ref="myAccessDecisionManagerBean">  
...  
</http>  

2.6. 驗證管理器和命名空間
主要接口提供了驗證服務在 Spring Security 中, 是 AuthenticationManager。 通常
是 Spring Security 中 ProviderManager 類的一個實例, 如果你以前使用過框架,你可
能已經很熟悉了。 如果沒有,它會在稍後被提及,在 #tech-intro-authentication。 bean
實例被使用authentication-manager 命名空間元素註冊。 你不能好似用一個自定義的
AuthenticationManager 如果你使用 HTTp 或方法安全,在命名空間中,但是它不應該
是一個問題, 因爲你完全控制了使用的 AuthenticationProvider。
你可能註冊額外的AuthenticationProviderbean, 在 ProviderManager 中,你可以使
用做這些事情,使用 ref 屬性, 這個屬性的值,是你希望
添加的 provider 的 bean 的名字,比如:

<authentication-manager>  
<authentication-providerrefauthentication-providerref="casAuthenticationProvider"/>  
</authentication-manager>  
<bean id="casAuthenticationProvider"  
class="org.springframework.security.cas.authentication.CasAuthenticationProvider">  
<security:custom-authentication-provider/>  
...  
</bean>  

另一個常見的需求是,上下文中的另一個 bean 可能需要引用AuthenticationManager。
你可以爲AuthenticationManager 註冊一個別名,然後在 applicationcontext 的其他
地方使用這個名字。

<security:authentication-manageraliassecurity:authentication-manageralias="authenticationManager">  
...  
</security:authentication-manager>  
<bean id="customizedFormLoginFilter"  
class="com.somecompany.security.web.CustomFormLoginFilter">  
<propertynamepropertyname="authenticationManager"ref="authenticationManager"/>  
...  
</bean>  
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章