亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

實現記住我功能

1. 前言

「記住我」這一功能多出現在互聯網應用中,其目的是為了減少用戶的認證次數和訪問門檻。在一般的內網應用、或者是安全性要求較高的管理后臺中出現使用頻度較低。

「記住我 Remember-me」也稱為「持續登錄 Persistent-login」, 主要用到了 Cookies 和 Token 技術,本節重點討論如何通過 Spring Security 配合出「記住我」的自動認證功能。

2. 記住我原理

圖片描述

「記住我」的核心思路是:將認證狀態以安全的方式保存在客戶端。

「記住我」需要通過向瀏覽器設置 Cookies 信息,這個 Cookies 信息未來會用于建立會話連接,并且提供自動登錄的能力。

「記住我」的基本流程為:

  1. 用戶通過瀏覽器登錄成功后,服務端生成一個可以持久化使用的 Token,并返回給瀏覽器;
  2. 瀏覽器端將該 Token 保存到 Cookies 中;
  3. 當用戶離開應用系統,并再次返回,此時服務端由于沒有了該用戶的登錄會話,所以要求用戶再次登錄;
  4. 瀏覽器檢查 Cookies 中是否包含「記住我」的 Token,如有,將其發送給服務端;
  5. 服務端驗證 Token,如果成功,直接返回登錄成功的結果。

3. 集成步驟

3.1 「記住我」Token 的存儲方式

通過前面描述我們看到,要實現「記住我」功能,關鍵在于如何安全的保護好用戶的認證信息 Token。Spring Security 提供了兩種「記住我」的實現方式:

  1. 使用 Hash 算法加密認證信息形成 Token,并將其保存在客戶端中;

  2. 將認證信息保存在數據庫中,并將查詢條件保存在客戶端中。

3.1.1 基于 Hash 的方式

基于 Hash 的方式是一種相對簡單的集成方式。這種方式利用 Hash 的特性,將「記住我」信息進行存檔。每當用戶認證通過,服務端便生成一條 Hash 記錄,并發送給客戶端瀏覽器,其中內容包括「用戶名」、「Token 過期時間」、「密碼」、「簽名秘鑰」。

發送的具體內容為:

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

username:          根據 UserDetailsService 配置得到用戶名信息。
password:          認證密碼,確保 UserDetailsService 中可以匹配到目標用戶。
expirationTime:    「記住我」Roken 的有效期,精確到毫秒。
key:               用于給 Token 簽名的密鑰信息,防止該 Token 被篡改。

發送出的 Token 只有到用戶下次需要登錄時才會被使用到,這期間,需要確保用戶名、密碼、密鑰等信息不被改變。還需要注意的是,「記住我」Token 在過期之前,可以在任何地方使用,因此其安全性上有一定的問題,如果使用數字認證一樣。當用戶認為自己的 Token 不在安全時,最好的辦法是立刻改變自己的認證密碼,并且使全部的「記住我」Token 失效。

啟動「記住我」功能僅需要一行配置,具體方式為:

<http>
...
<remember-me key="簽名密鑰"/>
</http>

當有多個 UserDetailsService 實例時,可以通過 user-service-ref 屬性指定唯一實例。

3.1.2 基于存儲的方式

使用數據庫作為 Token 存儲方式,需要在 <remember-me> 配置中增加 data-source-ref 屬性,配置方式如下:

<http>
...
<remember-me data-source-ref="數據源實例"/>
</http>

所用到的數據源需要包含 persistent_logins 數據表,其結構如下:

create table persistent_logins (username varchar(64) not null,
                                series varchar(64) primary key,
                                token varchar(64) not null,
                                last_used timestamp not null)

3.2 「記住我」相關接口及其實現

「記住我」需要配合「用戶名密碼認證過濾器」一起使用,觸發 RememberMeServices 實例實現其效果?!赣涀∥摇菇涌谥杏腥齻€主要方法,第一個名為 autoLogin 用于自動登錄審核,另外兩個是 loginFailloginSuccess 分別在認證失敗或成功時觸發。

具體表現形式為:

// 自動認證
Authentication autoLogin(HttpServletRequest request, HttpServletResponse response);

自動認證方法,在「記住我」功能啟用后,同時當前上下文中找不到用戶信息時觸發,我們需要根據不同的 Token 策略,實現「記住我」的判斷邏輯。

// 登錄失敗時觸發
void loginFail(HttpServletRequest request, HttpServletResponse response);
// 登錄成功時觸發
void loginSuccess(HttpServletRequest request, HttpServletResponse response,
    Authentication successfulAuthentication);

如前文所述,「記住我」有兩種 Token 策略,對應了兩種實現方法。

3.2.1 基于 Hash 方式的實現

先上代碼:

<bean id="rememberMeFilter" class=
"org.springframework.security.web.authentication.rememberme.RememberMeAuthenticationFilter">
<property name="rememberMeServices" ref="rememberMeServices"/>
<property name="authenticationManager" ref="theAuthenticationManager" />
</bean>

<bean id="rememberMeServices" class=
"org.springframework.security.web.authentication.rememberme.TokenBasedRememberMeServices">
<property name="userDetailsService" ref="myUserDetailsService"/>
<property name="key" value="springRocks"/>
</bean>

<bean id="rememberMeAuthenticationProvider" class=
"org.springframework.security.authentication.RememberMeAuthenticationProvider">
<property name="key" value="springRocks"/>
</bean>

基于 Hash 的方式需要配置三個核心 Bean 對象,分別是「過濾器」、「記住我處理服務」和「認證管理器」。這其中 TokenBasedRememberMeServices 負責生成 Token 內容,并交給「認證管理器」使用。

最后,要把處理服務 RememberMeServices 設置到用戶名密碼認證過濾器 UsernamePasswordAuthenticationFilter.setRememberMeServices() 里,將記住我的認證管理器添加到 AuthenticationManager.setProviders() 之中,將記住我過濾器添加到安全過濾鏈之中。

3.2.2 基于數據存儲方式的實現

使用數據存儲方式,其實現代碼與 Hash 方式基本相同,區別在于需要繼續配置 PersistentTokenRepository 來存取 Token,有兩個標準實現類:第一個是基于內存的 InMemoryTokenRepositoryImpl,第二個是基于 JDBC 的 JdbcTokenRepositoryImpl。通常情況下,第一種用于集成測試,第二種用于生產環境。

4. 小結

本節我們討論了「記住我」的原理及快速集成方式:

  • 「記住我」是一種基于 Token 的認證形式;
  • 「記住我」基于瀏覽器 Cookie 實現,在瀏覽器中保存從服務端獲取的,用于下次認證的 Token 內容;
  • 「記住我」是需要和用戶名密碼認證方式同時出現;
  • 「記住我」有兩種 Token 策略,一種基于 Hash 值,另外一種基于數據庫持久化。

下節我們討論,當系統對認證有特殊需求且無法由 Spring Security 安全框架提供時,如何實現使用外部方式認證,使用 Spring Security 管理認證結果及鑒權的方法。