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:允許方法調用,但必須在進入方法前過濾輸入值
復制代碼
@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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM