Spring Security 入門詳解(轉)

1.Spring Security介紹html

Spring Security是基於spring的應用程序提供聲明式安全保護的安全性框架,它提供了完整的安全性解決方案,可以在web請求級別和方法調用級別 處理身份證驗證和受權.它充分使用了依賴注入和麪向切面的技術.

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

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

2.Web請求級別的保護web

  對於請求級別的安全性來講,主要時經過保護一個或多個URL,使得只有特定的用戶才能訪問,並其餘用戶訪問該URL的內容.本文主要是基於spring mvc下整合Spring security模塊.正則表達式

2.1 聲明代理Servlet過濾器spring

  在web中的URL的通常須要過濾器進行保護,因此須要藉助一系列的Servlet過濾器提供各類各樣的安全性功能.這也須要在web.xml中配置一系列相關的<filter>,使得配置文件臃腫難以閱讀.因此Spring security提供了代理Servelt過濾器能夠解決該問題.以下面清單所示:sql

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和它所連接的其餘過濾器express

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:容許方法調用,但必須在進入方法前過濾輸入值
複製代碼
@PreAuthorize("hasRole('ROLE_ADMIN')")
public void addUser(User user){ //若是具備權限 ROLE_ADMIN 訪問該方法  .... } //returnObject能夠獲取返回對象user,判斷user屬性username是否和訪問該方法的用戶對象的用戶名同樣。不同則拋出異常。 @PostAuthorize("returnObject.user.username==principal.username") public User getUser(int userId){ //容許進入 ... return user; } //將結果過濾,即選出性別爲男的用戶 @PostFilter("returnObject.user.sex=='男' ") public List<User> getUserList(){ //容許進入 ... return user; }
複製代碼

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>

http://www.cnblogs.com/jaylon/p/4905769.html

Remember-Me功能

 

目錄

 

1.1     概述

1.2     基於簡單加密token的方法

1.3     基於持久化token的方法

1.4     Remember-Me相關接口和實現類

1.4.1    TokenBasedRememberMeServices

1.4.2    PersistentTokenBasedRememberMeServices

 

1.1          概述

       Remember-Me是指網站可以在Session之間記住登陸用戶的身份,具體來講就是我成功認證一次以後在必定的時間內我能夠不用再輸入用戶名和密碼進行登陸了,系統會自動給我登陸。這一般是經過服務端發送一個cookie給客戶端瀏覽器,下次瀏覽器再訪問服務端時服務端可以自動檢測客戶端的cookie,根據cookie值觸發自動登陸操做。Spring Security爲這些操做的發生提供必要的鉤子,而且針對於Remember-Me功能有兩種實現。一種是簡單的使用加密來保證基於cookie的token的安全,另外一種是經過數據庫或其它持久化存儲機制來保存生成的token。

       須要注意的是兩種實現都須要一個UserDetailsService。若是你使用的AuthenticationProvider不使用UserDetailsService,那麼記住我將會不起做用,除非在你的ApplicationContext中擁有一個UserDetailsService類型的bean。

 

1.2          基於簡單加密token的方法

       當用戶選擇了記住我成功登陸後,Spring Security將會生成一個cookie發送給客戶端瀏覽器。cookie值由以下方式組成:

base64(username+":"+expirationTime+":"+md5Hex(username+":"+expirationTime+":"+password+":"+key))

  • username:登陸的用戶名。
  • password:登陸的密碼。
  • expirationTime:token失效的日期和時間,以毫秒錶示。
  • key:用來防止修改token的一個key。

       這樣用來實現Remember-Me功能的token只能在指定的時間內有效,且必須保證token中所包含的username、password和key沒有被改變才行。須要注意的是,這樣作實際上是存在安全隱患的,那就是在用戶獲取到實現記住我功能的token後,任何用戶均可以在該token過時以前經過該token進行自動登陸。若是用戶發現本身的token被盜用了,那麼他能夠經過改變本身的登陸密碼來當即使其全部的記住我token失效。若是但願咱們的應用可以更安全一點,可使用接下來要介紹的持久化token方式,或者不使用Remember-Me功能,由於Remember-Me功能老是有點不安全的。

       使用這種方式時,咱們只須要在http元素下定義一個remember-me元素,同時指定其key屬性便可。key屬性是用來標記存放token的cookie的,對應上文提到的生成token時的那個key。

   <security:http auto-config="true">

      <security:form-login/>

      <!-- 定義記住我功能 -->

      <security:remember-me key="elim"/>

      <security:intercept-url pattern="/**" access="ROLE_USER" />

   </security:http>

 

       這裏有兩個須要注意的地方。第一,若是你的登陸頁面是自定義的,那麼須要在登陸頁面上新增一個名爲「_spring_security_remember_me」的checkbox,這是基於NameSpace定義提供的默認名稱,若是要自定義能夠本身定義TokenBasedRememberMeServices或PersistentTokenBasedRememberMeServices對應的bean,而後經過其parameter屬性進行指定,具體操做請參考後文關於《Remember-Me相關接口和實現類》部份內容。第二,上述功能須要一個UserDetailsService,若是在你的ApplicationContext中已經擁有一個了,那麼Spring Security將自動獲取;若是沒有,那麼固然你須要定義一個;若是擁有在ApplicationContext中擁有多個UserDetailsService定義,那麼你須要經過remember-me元素的user-service-ref屬性指定將要使用的那個。如:

   <security:http auto-config="true">

      <security:form-login/>

      <!-- 定義記住我功能,經過user-service-ref指定將要使用的UserDetailsService-->

      <security:remember-me key="elim" user-service-ref="userDetailsService"/>

      <security:intercept-url pattern="/**" access="ROLE_USER" />

   </security:http>

  

   <bean id="userDetailsService"class="org.springframework.security.core.userdetails.jdbc.JdbcDaoImpl">

      <property name="dataSource" ref="dataSource"/>

   </bean>

 

1.3          基於持久化token的方法

       持久化token的方法跟簡單加密token的方法在實現Remember-Me功能上大致相同,都是在用戶選擇了「記住我」成功登陸後,將生成的token存入cookie中併發送到客戶端瀏覽器,待到下次用戶訪問系統時,系統將直接從客戶端cookie中讀取token進行認證。所不一樣的是基於簡單加密token的方法,一旦用戶登陸成功後,生成的token將在客戶端保存一段時間,若是用戶不點擊退出登陸,或者不修改密碼,那麼在cookie失效以前,他均可以使用該token進行登陸,哪怕該token被別人盜用了,用戶與盜用者都一樣能夠進行登陸。而基於持久化token的方法採用這樣的實現邏輯:

       (1)用戶選擇了「記住我」成功登陸後,將會把username、隨機產生的序列號、生成的token存入一個數據庫表中,同時將它們的組合生成一個cookie發送給客戶端瀏覽器。

       (2)當下一次沒有登陸的用戶訪問系統時,首先檢查cookie,若是對應cookie中包含的username、序列號和token與數據庫中保存的一致,則表示其經過驗證,系統將從新生成一個新的token替換數據庫中對應組合的舊token,序列號保持不變,同時刪除舊的cookie,從新生成包含新生成的token,就的序列號和username的cookie發送給客戶端。

       (3)若是檢查cookie時,cookie中包含的username和序列號跟數據庫中保存的匹配,可是token不匹配。這種狀況極有多是由於你的cookie被人盜用了,因爲盜用者使用你本來經過認證的cookie進行登陸了致使舊的token失效,而產生了新的token。這個時候Spring Security就能夠發現cookie被盜用的狀況,它將刪除數據庫中與當前用戶相關的全部token記錄,這樣盜用者使用原有的cookie將不能再登陸,同時提醒用戶其賬號有被盜用的可能性。

       (4)若是對應cookie不存在,或者包含的username和序列號與數據庫中保存的不一致,那麼將會引導用戶到登陸頁面。

       從以上邏輯咱們能夠看出持久化token的方法比簡單加密token的方法更安全,由於一旦你的cookie被人盜用了,你只要再利用原有的cookie試圖自動登陸一次,原有的token將失效致使盜用者不能再使用原來盜用的cookie進行登陸了,同時用戶能夠發現本身的cookie有被盜用的可能性。但由於cookie被盜用後盜用者還能夠在用戶下一次登陸前順利的進行登陸,因此若是你的應用對安全性要求比較高就不要使用Remember-Me功能了。

    使用持久化token方法時須要咱們的數據庫中擁有以下表及其表結構。

create table persistent_logins (username varchar(64) not null,

                                    series varchar(64) primary key,

                                    token varchar(64) not null,

                                    last_used timestamp not null)

 

    而後仍是經過remember-me元素來使用,只是這個時候咱們須要其data-source-ref屬性指定對應的數據源,同時別忘了它也一樣須要ApplicationContext中擁有UserDetailsService,若是擁有多個,請使用user-service-ref屬性指定remember-me使用的是哪個。

   <security:http auto-config="true">

      <security:form-login/>

      <!-- 定義記住我功能 -->

      <security:remember-me data-source-ref="dataSource"/>

      <security:intercept-url pattern="/**" access="ROLE_USER" />

   </security:http>

 

1.4     Remember-Me相關接口和實現類

在上述介紹中,咱們實現Remember-Me功能是經過Spring Security爲了簡化Remember-Me而提供的NameSpace進行定義的。而底層實際上仍是經過RememberMeServices、UsernamePasswordAuthenticationFilter和RememberMeAuthenticationFilter的協做來完成的。RememberMeServices是Spring Security爲Remember-Me提供的一個服務接口,其定義以下。

publicinterface RememberMeServices {

    /**

     * 自動登陸。在實現這個方法的時候應該判斷用戶提供的Remember-Me cookie是否有效,若是無效,應當直接忽略。

     * 若是認證成功應當返回一個AuthenticationToken,推薦返回RememberMeAuthenticationToken;

     * 若是認證不成功應當返回null。

     */

    Authentication autoLogin(HttpServletRequest request, HttpServletResponse response);

    /**

     * 在用戶登陸失敗時調用。實現者應當作一些相似於刪除cookie之類的處理。

     */

    void loginFail(HttpServletRequest request, HttpServletResponse response);

    /**

     * 在用戶成功登陸後調用。實現者能夠在這裏判斷用戶是否選擇了「Remember-Me」登陸,而後作相應的處理。

     */

    void loginSuccess(HttpServletRequest request, HttpServletResponse response,

        Authentication successfulAuthentication);

}

 

       UsernamePasswordAuthenticationFilter擁有一個RememberMeServices的引用,默認是一個空實現的NullRememberMeServices,而實際當咱們經過remember-me定義啓用Remember-Me時,它會是一個具體的實現。用戶的請求會先經過UsernamePasswordAuthenticationFilter,如認證成功會調用RememberMeServices的loginSuccess()方法,不然調用RememberMeServices的loginFail()方法。UsernamePasswordAuthenticationFilter是不會調用RememberMeServices的autoLogin()方法進行自動登陸的。以後運行到RememberMeAuthenticationFilter時若是檢測到尚未登陸,那麼RememberMeAuthenticationFilter會嘗試着調用所包含的RememberMeServices的autoLogin()方法進行自動登陸。關於RememberMeServices Spring Security已經爲咱們提供了兩種實現,分別對應於前文提到的基於簡單加密token和基於持久化token的方法。

 

1.4.1   TokenBasedRememberMeServices

       TokenBasedRememberMeServices對應於前文介紹的使用namespace時基於簡單加密token的實現。TokenBasedRememberMeServices會在用戶選擇了記住我成功登陸後,生成一個包含token信息的cookie發送到客戶端;若是用戶登陸失敗則會刪除客戶端保存的實現Remember-Me的cookie。須要自動登陸時,它會判斷cookie中所包含的關於Remember-Me的信息是否與系統一致,一致則返回一個RememberMeAuthenticationToken供RememberMeAuthenticationProvider處理,不一致則會刪除客戶端的Remember-Me cookie。TokenBasedRememberMeServices還實現了Spring Security的LogoutHandler接口,因此它能夠在用戶退出登陸時當即清除Remember-Me cookie。

 

       若是把使用namespace定義Remember-Me改成直接定義RememberMeServices和對應的Filter來使用的話,那麼咱們能夠以下定義。

   <security:http>

      <security:form-login login-page="/login.jsp"/>

      <security:intercept-url pattern="/login*.jsp*"access="IS_AUTHENTICATED_ANONYMOUSLY"/>

      <security:intercept-url pattern="/**" access="ROLE_USER" />

      <!-- 把usernamePasswordAuthenticationFilter加入FilterChain -->

      <security:custom-filter ref="usernamePasswordAuthenticationFilter"before="FORM_LOGIN_FILTER"/>

      <security:custom-filter ref="rememberMeFilter" position="REMEMBER_ME_FILTER"/>

   </security:http>

   <!-- 用於認證的AuthenticationManager -->

   <security:authentication-manager alias="authenticationManager">

      <security:authentication-provider

         user-service-ref="userDetailsService"/>

      <security:authentication-provider ref="rememberMeAuthenticationProvider"/>

   </security:authentication-manager>

 

   <bean id="userDetailsService"

      class="org.springframework.security.core.userdetails.jdbc.JdbcDaoImpl">

      <property name="dataSource" ref="dataSource" />

   </bean>

 

   <bean id="usernamePasswordAuthenticationFilter"class="org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter">

      <property name="rememberMeServices" ref="rememberMeServices"/>

      <property name="authenticationManager" ref="authenticationManager"/>

      <!-- 指定request中包含的用戶名對應的參數名 -->

      <property name="usernameParameter" value="username"/>

      <property name="passwordParameter" value="password"/>

      <!-- 指定登陸的提交地址 -->

      <property name="filterProcessesUrl" value="/login.do"/>

   </bean>

   <!-- Remember-Me對應的Filter -->

   <bean id="rememberMeFilter"

   class="org.springframework.security.web.authentication.rememberme.RememberMeAuthenticationFilter">

      <property name="rememberMeServices" ref="rememberMeServices" />

      <property name="authenticationManager" ref="authenticationManager" />

   </bean>

   <!-- RememberMeServices的實現 -->

   <bean id="rememberMeServices"

   class="org.springframework.security.web.authentication.rememberme.TokenBasedRememberMeServices">

      <property name="userDetailsService" ref="userDetailsService" />

      <property name="key" value="elim" />

      <!-- 指定request中包含的用戶是否選擇了記住個人蔘數名 -->

      <property name="parameter" value="rememberMe"/>

   </bean>

   <!-- key值需與對應的RememberMeServices保持一致 -->

   <bean id="rememberMeAuthenticationProvider"

   class="org.springframework.security.authentication.RememberMeAuthenticationProvider">

      <property name="key" value="elim" />

   </bean>

 

       須要注意的是RememberMeAuthenticationProvider在認證RememberMeAuthenticationToken的時候是比較它們擁有的key是否相等,而RememberMeAuthenticationToken的key是TokenBasedRememberMeServices提供的,因此在使用時須要保證RememberMeAuthenticationProvider和TokenBasedRememberMeServices的key屬性值保持一致。須要配置UsernamePasswordAuthenticationFilter的rememberMeServices爲咱們定義好的TokenBasedRememberMeServices,把RememberMeAuthenticationProvider加入AuthenticationManager的providers列表,並添加RememberMeAuthenticationFilter和UsernamePasswordAuthenticationFilter到FilterChainProxy。

 

1.4.2   PersistentTokenBasedRememberMeServices

       PersistentTokenBasedRememberMeServices是RememberMeServices基於前文提到的持久化token的方式實現的。具體實現邏輯跟前文介紹的以NameSpace的方式使用基於持久化token的Remember-Me是同樣的,這裏就再也不贅述了。此外,若是單獨使用,其使用方式和上文描述的TokenBasedRememberMeServices是同樣的,這裏也再也不贅述了。

       須要注意的是PersistentTokenBasedRememberMeServices是須要將token進行持久化的,因此咱們必須爲其指定存儲token的PersistentTokenRepository。Spring Security對此有兩種實現,InMemoryTokenRepositoryImpl和JdbcTokenRepositoryImpl。前者是將token存放在內存中的,一般用於測試,然後者是將token存放在數據庫中。PersistentTokenBasedRememberMeServices默認使用的是前者,咱們能夠經過其tokenRepository屬性來指定使用的PersistentTokenRepository。

       使用JdbcTokenRepositoryImpl時咱們可使用在前文提到的默認表結構。若是須要使用自定義的表,那麼咱們能夠對JdbcTokenRepositoryImpl進行重寫。定義JdbcTokenRepositoryImpl時須要指定一個數據源dataSource,同時能夠經過設置參數createTableOnStartup的值來控制是否要在系統啓動時建立對應的存入token的表,默認建立語句爲「create table persistent_logins (username varchar(64) not null, series varchar(64) primary key, token varchar(64) not null, last_used timestamp not null)」,可是若是自動建立時對應的表已經存在於數據庫中,則會拋出異常。createTableOnStartup屬性默認爲false。

       直接顯示地使用PersistentTokenBasedRememberMeServices和上文提到的直接顯示地使用TokenBasedRememberMeServices的方式是同樣的,咱們只須要將上文提到的配置中RememberMeServices實現類TokenBasedRememberMeServices換成PersistentTokenBasedRememberMeServices便可。

   <!-- RememberMeServices的實現 -->

   <bean id="rememberMeServices"

   class="org.springframework.security.web.authentication.rememberme.PersistentTokenBasedRememberMeServices">

      <property name="userDetailsService" ref="userDetailsService" />

      <property name="key" value="elim" />

      <!-- 指定request中包含的用戶是否選擇了記住個人蔘數名 -->

      <property name="parameter" value="rememberMe"/>

      <!-- 指定PersistentTokenRepository -->

      <property name="tokenRepository">

         <beanclass="org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl">

            <!-- 數據源 -->

            <property name="dataSource" ref="dataSource"/>

            <!-- 是否在系統啓動時建立持久化token的數據庫表 -->

            <property name="createTableOnStartup" value="false"/>

         </bean>

      </property>

   </bean>

 

(注:本文是基於Spring Security3.1.6所寫)

(注:原創文章,轉載請註明出處。原文地址:http://elim.iteye.com/blog/2163997

http://elim.iteye.com/blog/2163997

相關文章
相關標籤/搜索