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

file

本文是Spring Security系列中的一篇。在上一篇文章中,咱們經過實現UserDetailsService和UserDetails接口,實現了動態的從數據庫加載用戶、角色、權限相關信息,從而實現了登陸及受權相關的功能。這一節就在此基礎上新增,登陸過程當中常用的「記住我」功能,也就是咱們常常會在各類網站登錄時見到的"兩週內免登陸",「三天內免登陸」的功能。該功能的做用就是:當咱們登陸成功以後,必定的週期內當咱們再次訪問該網站,不須要從新登陸。spring

1、最簡實踐

其實實現這個功能很是簡單,只須要咱們在重寫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周內免登陸。安全

2、實現原理

不少朋友可能看了上面的實現過程內心都犯懵,這樣就實現了?下面和你們說明一下這過程當中間,都作了哪些事情。springboot

  • 當咱們登錄的時候,除了用戶名、密碼,咱們還能夠勾選remember-me。
  • 若是咱們勾選了remember-me,當咱們登陸成功以後服務端會生成一個Cookie返回給瀏覽器,這個Cookie的名字默認是remember-me;值是一個token令牌。
  • 當咱們在有效期內再次訪問應用時,通過RememberMeAuthenticationFilter,讀取Cookie中的token進行驗證。驗正經過不須要再次登陸就能夠進行應用訪問。

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

file

RememberMeAuthenticationFilter在Spring Security過濾器鏈中處於總體偏後的位置,因此只有當各類傳統的登陸方式都沒法完成驗證的狀況下,才走RememberMeAuthenticationFilter,這也是符合實際需求的。app

3、個性化配置

在實際的開發過程當中,咱們還能夠根據需求作一些個性化的設置,以下:ide

.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。

file

4、token數據庫存儲方式

上面咱們講的方式,就是最簡單的實現「記住我-自動登陸」功能的方式。這種方式的缺點在於:token與用戶的對應關係是在內存中存儲的,當咱們重啓應用以後全部的token都將消失,即:全部的用戶必須從新登錄。爲此,Spring Security還給咱們提供了一種將token存儲到數據庫中的方式,重啓應用也不受影響。學習

> 有的文章說使用數據庫存儲方式是由於這種方式更安全,筆者不這麼認爲。雖然數據庫存儲的token的確再也不是用戶名、密碼MD5加密字符串了,而是一個隨機序列號。可是一旦你的隨機序列號cookie被劫持,效果是同樣的。比如你家有把密碼鎖:你把鑰匙丟了和你把密碼丟了,危害性是同樣的。網站

file

上圖是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())

期待您的關注

相關文章
相關標籤/搜索