史上最簡單的Spring Security教程(三十六):RememberMeAuthenticationFilter詳解

銀河架構師發表於2020-10-19

 

前面我們講了 記住我 登入方式,以及和其它登入方式相融合的多種登入形式,想必對 記住我 登入方式有了一個大致清晰的瞭解。本次我們就來說一下其中一個比較重要的 Filter,即 RememberMeAuthenticationFilter

RememberMeAuthenticationFilter 是 記住我 登入方式比較重要的類,其主要功能有 自動登入身份認證登入成功事件釋出異常處理/登入失敗 等。

另外,重要的一點是,該 Filter 執行有一個條件,就是當前使用者尚未認證

if (SecurityContextHolder.getContext().getAuthentication() == null) {
    ......
}

下面就這幾項重要功能分別加以說明。

噹噹前使用者尚未登入時,先執行 自動登入 邏輯,即先呼叫 RememberMeServices 的 autoLogin 方法。

Authentication rememberMeAuth = rememberMeServices.autoLogin(request,
          response);

如果 rememberMeAuth 不為 null,則再執行身份認證。

rememberMeAuth = authenticationManager.authenticate(rememberMeAuth);

沒忘了 AuthenticationManager 吧?前面詳細講過:史上最簡單的Spring Security教程(二十七):AuthenticationManager預設實現之ProviderManager詳解

身份認證成功(不發生異常)後,先將當前 Authentication 設定到 SecurityContextHolder 上下文中,然後再執行成功登入邏輯。

// Store to SecurityContextHolder
SecurityContextHolder.getContext().setAuthentication(rememberMeAuth);
​
onSuccessfulAuthentication(request, response, rememberMeAuth);

之後,便呼叫時間釋出器,釋出相關事件

// Fire event
if (this.eventPublisher != null) {
    eventPublisher
        .publishEvent(new InteractiveAuthenticationSuccessEvent(
            SecurityContextHolder.getContext()
            .getAuthentication(), this.getClass()));
}

然後,如果設定了 AuthenticationSuccessHandler ,則呼叫成功登入邏輯。沒忘了 AuthenticationSuccessHandler 的用法吧?之前我們同樣也介紹過:史上最簡單的Spring Security教程(五):成功登入SuccessHandler高階用法

此外,如果想跳轉到某個特定頁面,而不是使用者一開始訪問的頁面,怎麼辦呢?同樣是在 AuthenticationSuccessHandler 中設定 defaultTargetUrl ,之前也詳細講解過,並且也畫了一個詳細的流程圖:史上最簡單的Spring Security教程(四):成功登入頁面

接下來,便是異常處理/登入失敗了。捕獲到身份認證過程中的異常後,進行 異常處理/登入失敗 相關處理

catch (AuthenticationException authenticationException) {
    if (logger.isDebugEnabled()) {
        logger.debug(
            "SecurityContextHolder not populated with remember-me token, as "
            + "AuthenticationManager rejected Authentication returned by RememberMeServices: '"
            + rememberMeAuth
            + "'; invalidating remember-me token",
            authenticationException);
    }
​
    rememberMeServices.loginFail(request, response);
​
    onUnsuccessfulAuthentication(request, response,
                                 authenticationException);
}

最後,如果不滿足該 Filter 觸發條件,即當前使用者已經身份認證完成或存在其身份認證資訊,或者 呼叫 自動登入 後得不到相應的結果,即 自動登入 失敗,便會呼叫後續的 Filter。

else {
    if (logger.isDebugEnabled()) {
        logger.debug("SecurityContextHolder not populated with remember-me token, as it already contained: '"
                     + SecurityContextHolder.getContext().getAuthentication() + "'");
    }
​
    chain.doFilter(request, response);
}

如果想自定義 登入成功 、登入失敗(注意不是AuthenticationSuccessHandler、AuthenticationFailureHandler 怎麼辦呢?當然是一樣的邏輯咯,繼承此 Filter 後,實現兩個方法即可。

protected void onSuccessfulAuthentication(HttpServletRequest request,
      HttpServletResponse response, Authentication authResult) {
}
​
......
    
protected void onUnsuccessfulAuthentication(HttpServletRequest request,
      HttpServletResponse response, AuthenticationException failed) {
}

RememberMeAuthenticationFilter 的主要功能介紹完畢。

其它詳細原始碼,請參考文末原始碼連結,可自行下載後閱讀。

我是銀河架構師,十年飲冰,難涼熱血,願歷盡千帆,歸來仍是少年! 

如果文章對您有幫助,請舉起您的小手,輕輕【三連】,這將是筆者持續創作的動力源泉。當然,如果文章有錯誤,或者您有任何的意見或建議,請留言。感謝您的閱讀!

 

原始碼

 

github

https://github.com/liuminglei/SpringSecurityLearning/tree/master/36

gitee

https://gitee.com/xbd521/SpringSecurityLearning/tree/master/36

 

 

 

相關文章