當(dāng)用戶勾選了記住我選項(xiàng)并登錄成功后,Spring Security會(huì)生成一個(gè)token標(biāo)識(shí),然后將該token標(biāo)識(shí)持久化到數(shù)據(jù)庫,并且生成一個(gè)與該token相對(duì)應(yīng)的cookie返回給瀏覽器。當(dāng)用戶過段時(shí)間再次訪問系統(tǒng)時(shí),如果該cookie沒有過期,Spring Security便會(huì)根據(jù)cookie包含的信息從數(shù)據(jù)庫中獲取相應(yīng)的token信息,然后幫用戶自動(dòng)完成登錄操作。
其實(shí)數(shù)據(jù)庫和cookie中存儲(chǔ)的token就是用戶名,數(shù)據(jù)庫中的是經(jīng)過加密的,spring security會(huì)將它們兩進(jìn)行轉(zhuǎn)化的,不用我們操作,
Spring Security的記住我功能的實(shí)現(xiàn)需要使用數(shù)據(jù)庫來持久化token。
- 修改MySecurityConfig配置token持久化對(duì)象
@Component
public class MySecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private MyAuthenticationFailureHandler authenticationFailureHandler;
@Autowired
private MyAuthenticationSuccessHandler authenticationSuccessHandler;
@Autowired
private ValidateCodeFilter validateCodeFilter;
@Autowired
private UserDetailService userDetailService;
@Autowired
private DataSource dataSource;
public PersistentTokenRepository persistentTokenRepository() {
JdbcTokenRepositoryImpl jdbcTokenRepository = new JdbcTokenRepositoryImpl();
jdbcTokenRepository.setDataSource(dataSource);
//如果表已存在會(huì)報(bào)錯(cuò)
jdbcTokenRepository.setCreateTableOnStartup(false);
return jdbcTokenRepository;
}
@Bean
public BCryptPasswordEncoder bCryptPasswordEncoder(){
return new BCryptPasswordEncoder();
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.addFilterBefore(validateCodeFilter, UsernamePasswordAuthenticationFilter.class) // 添加驗(yàn)證碼校驗(yàn)過濾器
.formLogin() // 表單登錄
// http.httpBasic() // HTTP Basic
.loginPage("/authentication/require") // 登錄跳轉(zhuǎn) URL
.loginProcessingUrl("/login") // 處理表單登錄 URL
.failureHandler(authenticationFailureHandler) // 處理登錄失敗
.successHandler(authenticationSuccessHandler)
.and()
.rememberMe() // 啟用rememberMe
.tokenRepository(persistentTokenRepository()) // 配置 token 持久化倉庫
.tokenValiditySeconds(3600) // remember 過期時(shí)間,單為秒
.userDetailsService(userDetailService) // 處理自動(dòng)登錄邏輯
.and()
.authorizeRequests() // 授權(quán)配置
.antMatchers("/authentication/require",
"/login.html",
"/code/image").permitAll() // 無需認(rèn)證的請(qǐng)求路徑
.anyRequest() // 所有請(qǐng)求
.authenticated() // 都需要認(rèn)證
.and().csrf().disable();
}
}
- 修改login.html(記住我的標(biāo)簽 name="remember-me"否則會(huì)報(bào)錯(cuò)),也可以在上面的配置類中增加
.rememberMeParameter("rmb") 來自定義rememberMe的參數(shù)
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>登錄</title>
</head>
<body>
<form class="login-page" action="/login" method="post">
<div class="form">
<h3>賬戶登錄</h3>
<input type="text" placeholder="用戶名" name="username" required="required" >
<input type="password" placeholder="密碼" name="password" required="required" >
<input type="text" name="imageCode" placeholder="驗(yàn)證碼" style="width: 50%;"/>
<img src="/code/image"/>
<input type="checkbox" name="remember-me"/> 記住我
<button type="submit">登錄</button>
</div>
</form>
</body>
</html>