1. 程式人生 > >Spring Security框架下實現兩週內自動登入"記住我"功能

Spring Security框架下實現兩週內自動登入"記住我"功能

本文是Spring Security系列中的一篇。在上一篇文章中,我們通過實現UserDetailsService和UserDetails介面,實現了動態的從資料庫載入使用者、角色、許可權相關資訊,從而實現了登入及授權相關的功能。這一節就在此基礎上新增,登入過程中經常使用的“記住我”功能,也就是我們經常會在各種網站登陸時見到的"兩週內免登入",“三天內免登入”的功能。該功能的作用就是:當我們登入成功之後,一定的週期內當我們再次訪問該網站,不需要重新登入。

一、最簡實踐

其實實現這個功能非常簡單,只需要我們在重寫WebSecurityConfigurerAdapter 方法配置HttpSecurity 的時候增加rememberMe()方法。(下面程式碼中省略了大量的關於Spring Security登入驗證的配置,在本號此前的文章中已經講過)

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.rememberMe();   //實現記住我自動登入配置,核心的程式碼只有這一行
    }
}

然後在登入表單中加入一個checkbox勾選框,name屬性的值目前必須是“remember-me”(個性化更改的方法後面會講)。


<label><input type="checkbox" name="remember-me"/>自動登入</label>

就是這麼簡單,我們就實現了記住我功能,預設效果是:2周內免登入。

二、實現原理

很多朋友可能看了上面的實現過程心裡都犯懵,這樣就實現了?下面和大家說明一下這過程中間,都做了哪些事情。

  • 當我們登陸的時候,除了使用者名稱、密碼,我們還可以勾選remember-me。
  • 如果我們勾選了remember-me,當我們登入成功之後服務端會生成一個Cookie返回給瀏覽器,這個Cookie的名字預設是remember-me;值是一個token令牌。
  • 當我們在有效期內再次訪問應用時,經過RememberMeAuthenticationFilter,讀取Cookie中的token進行驗證。驗正通過不需要再次登入就可以進行應用訪問。

這個token令牌是一個 MD5 hash字串:包含username、expirationTime和passwod和一個預定義的key,並將他們經過MD5加密。可能有的朋友會問:這樣安全麼?如果cookie被劫持,一定是不安全的,別人拿到了這個字串在有效期內就可以訪問你的應用。這就和你的鑰匙token被盜了,你家肯定不安全是一個道理。 但是不存在密碼被破解為明文的可能性,MD5 hash是不可逆的。

RememberMeAuthenticationFilter在Spring Security過濾器鏈中處於整體偏後的位置,所以只有當各種傳統的登入方式都無法完成驗證的情況下,才走RememberMeAuthenticationFilter,這也是符合實際需求的。

三、個性化配置

在實際的開發過程中,我們還可以根據需求做一些個性化的設定,如下:

.rememberMe()
    .rememberMeParameter("remember-me-new")
    .rememberMeCookieName("remember-me-cookie")
    .tokenValiditySeconds(2 * 24 * 60 * 60);  
  • tokenValiditySeconds用於設定token的有效期,即多長時間內可以免除重複登入,單位是秒。不修改配置情況下預設是2周。
  • 通過rememberMeParameter設定from表單“自動登入”勾選框的引數名稱。如果這裡改了,from表單中checkbox的name屬性要對應的更改。如果不設定預設是remember-me。
  • rememberMeCookieName設定了儲存在瀏覽器端的cookie的名稱,如果不設定預設也是remember-me。如下圖中檢視瀏覽器的cookie。

四、token資料庫儲存方式

上面我們講的方式,就是最簡單的實現“記住我-自動登入”功能的方式。這種方式的缺點在於:token與使用者的對應關係是在記憶體中儲存的,當我們重啟應用之後所有的token都將消失,即:所有的使用者必須重新登陸。為此,Spring Security還給我們提供了一種將token儲存到資料庫中的方式,重啟應用也不受影響。

有的文章說使用資料庫儲存方式是因為這種方式更安全,筆者不這麼認為。雖然資料庫儲存的token的確不再是使用者名稱、密碼MD5加密字串了,而是一個隨機序列號。但是一旦你的隨機序列號cookie被劫持,效果是一樣的。好比你家有把密碼鎖:你把鑰匙丟了和你把密碼丟了,危害性是一樣的。

上圖是token資料庫儲存方式的實現原理和驗證過程,下面我們就來實現一下。首先,我們需要鍵一張資料庫表persistent_logins:

CREATE TABLE `persistent_logins` (
  `username` varchar(64) NOT NULL,
  `series` varchar(64) NOT NULL,
  `token` varchar(64) NOT NULL,
  `last_used` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`series`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

初始化一個PersistentTokenRepository型別的Spring bean,並將系統使用的DataSource注入到該bean中。(當然前提一定是你已經在Spring Boot的application.yml中配置好DataSource相關的連線屬性,這裡不再贅述)

@Autowired
private DataSource dataSource;

 @Bean
 public PersistentTokenRepository persistentTokenRepository(){
     JdbcTokenRepositoryImpl tokenRepository = new JdbcTokenRepositoryImpl();
     tokenRepository.setDataSource(dataSource);
     return tokenRepository;
 }

最後在Spring Security配置方法configure(HttpSecurity http)加上如下的個性化配置:

.rememberMe()
    .tokenRepository(persistentTokenRepository())

期待您的關注

  • 向您推薦博主的系列文件:《手摸手教您學習SpringBoot系列-16章97節》
  • 本文轉載註明出處(必須帶連線,不能只轉文字):字母哥部落格。