本章的代碼實現是在上一篇教程:精通Spring Boot——第十九篇:Spring Security 整合驗證碼登陸基礎上,若是感受本篇跳躍幅度較大,可先閱讀上一篇,或訪問個人github.com(文末會附上地址),下載源碼閱讀。html
Spring Security記住我功能的基本原理: 首先當咱們的瀏覽器發送請求到UsernamePasswordAuthenticationFilter時,若是認證成功的話,會調用一個RememberMeService服務, 在RememberMeService中,存在一個TokenRepository,它會將token寫入到瀏覽器的cookie中,並將token同時寫入到數據庫。當用戶在下一次從新登陸時,服務請求會通過RememberMeAuthentionFilter,這個filter會讀取瀏覽器Cookie中的token,而後再傳遞給RememberMeService, RememberMeService再去數據庫中查詢該token是否有效,若該token有效,則會取出對應的用戶名,再去調用UserDetailsService獲取用戶信息,再將用戶信息放入SecurityContext裏面。 java
---圖片來源網絡git
RememberMeAuthentionFilter在Spring Security過濾器鏈中處於AuthenticationFileter中的最後,當其餘驗證方式沒法驗證用戶信息時,纔會調用RememberMeAuthentionFilter類來驗證用戶信息。 github
---圖片來源網絡web
要實現記住我功能,在Spring Security中操做比較簡單,只須要實例化PersistentTokenRepository,而後在配置中增長rememberMe配置就行,具體代碼實現以下:spring
import com.linking.springsecurityremeberme.filter.CaptchaFilter; import com.linking.springsecurityremeberme.handler.MyFailureHandler; import com.linking.springsecurityremeberme.service.impl.UserDetailsServiceImpl; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl; import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository; import javax.sql.DataSource; /** * @author developlee * @since 2019/1/18 15:30 */ @Configuration public class SecurityConfig extends WebSecurityConfigurerAdapter { @Autowired private UserDetailsServiceImpl userDetailsService; @Autowired private DataSource dataSource; @Bean public PersistentTokenRepository tokenRepository() { JdbcTokenRepositoryImpl jdbcTokenRepository = new JdbcTokenRepositoryImpl(); jdbcTokenRepository.setDataSource(dataSource); // 設置爲true,則項目啓動時,會在對應數據源中自動建表token表 jdbcTokenRepository.setCreateTableOnStartup(false); return jdbcTokenRepository; } @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } @Autowired private AppConfig appConfig; @Override protected void configure(HttpSecurity http) throws Exception { http.formLogin().loginPage("/sign_in").loginProcessingUrl(appConfig.getLoginUri()) .defaultSuccessUrl("/welcome").permitAll() .failureHandler(new MyFailureHandler()) .and().authorizeRequests().antMatchers("/code/image").permitAll() .and().addFilterBefore(new CaptchaFilter(appConfig, new MyFailureHandler()), UsernamePasswordAuthenticationFilter.class) .logout().logoutUrl("/auth/logout").clearAuthentication(true) .and().rememberMe().tokenRepository(tokenRepository())//設置tokenRepository .alwaysRemember(true) // 老是記住,會刷新過時時間 .tokenValiditySeconds(300)// 設置過時時間爲5分鐘 .userDetailsService(userDetailsService) // 設置userDetailsService,用來獲取username .and().authorizeRequests().anyRequest().authenticated(); } }
在頁面中,新增記住我sql
<span><input name="rememberMe" type="checkbox" th:value="true">記住我</span>
通過上面的步驟,咱們基本上已經完成了如何添加記住我功能,接下來咱們在頁面上輸入用戶名和密碼,並同時點擊記住我。登陸成功後,會跳轉至welcome.html頁。而後重啓系統,清空服務器session, 再次去訪問welcome.html,看看可否直接訪問。 點擊登陸,已經成功跳轉到welcome.html,重啓清空session,直接在地址輸入http:localhost:8080/welcome.html 直接可以訪問,說明在請求在通過Spring Security過濾器鏈時,讀取了cookies中的token,並經過token去查找了用戶的信息,再經過userDetailsService進行了登陸。數據庫
OK,咱們先從第一步登陸操做開始提及,第一次登陸時,必然會通過UsernamePasswordAuthenticationFilter,因此把斷點設置在該類中 而後接着代碼走走走,下一步來到successfulAuthentication這個方法,也就是登陸成功後的處理方法,能夠看到這裏rememberService會將登陸成功的用戶信息保存
瀏覽器
OK,再接着走,看下這個rememberService.onLoginSuccess具體實現 能夠看到,這個方法,會將一條token記錄插入到數據庫中,並寫入到Cookie。到這裏爲止,登陸操做基本已經完成。 接下來從新啓動下服務,並直接訪問welcome.html,看看代碼的執行順序如何。斷點要打在RememberMeService中的autoLogin方法。 看下實現,首先是判斷cookie是否爲null和爲空,接着往下走,來到decodeCookie解析cookie,而後經過processAutoLoginCookie這個方法,去數據庫中經過cookieToken查詢用戶信息,接下來再對用戶信息進行校驗(用戶更換了密碼之類的狀況),check成功後,再執行登陸操做,寫入用戶信息到SecurityContext中。
服務器
如下是processAutoLoginCookie方法的具體實現。
在Spring Security中實現記住我功能有兩種實現,一種是上面介紹的PersistentTokenBasedRememberMeService,一種是TokenBasedRememberService。 這兩種的區別主要在於什麼呢? 它們是AbstractRememberMeServices.onLoginSuccess方法的不一樣實現。 上面介紹的PersistentTokenBasedRememberMeService,是生成token的key,expireTime等信息保存在數據庫中的,而TokenBasedRememberService則是將key,expireTime等信息保存在客戶端(瀏覽器)中的,驗證方式也全部不一樣。 看下TokenBasedRememberService中對token的驗證明現,大概能夠得出這樣的結論
這篇的內容主要目的是爲系統增長‘記住我’功能,相對比較簡單,代碼的編寫量也比較少。在本篇咱們也分析了一下Spring Security中實現這個功能的源碼,須要實現的主要是PersistentTokenRepository,並在配置中增長RememberMe的配置。 本篇的源代碼可在個人github.com中找到,歡迎你們star 精通Spring Boot系列和follow我本人,也能夠加我本人微信探討技術,感謝您觀看此文,謝謝!