版权声明:士,不可以不弘毅,任重而道远 https://blog.csdn.net/superbeyone/article/details/84728370
文章目录
Spring Security 记住我功能基本原理,实现及源码追踪
1. 流程分析
2. 过滤器链
3. 代码实现
3.1 页面
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>登录</title>
</head>
<body>
<h2>标准登录页面</h2>
<h3>表单登录</h3>
<form action="/authentication/form" method="post">
<table>
<tr>
<td>用户名:</td>
<td><input type="text" name="username" id="username"></td>
</tr>
<tr>
<td>密码:</td>
<td><input type="password" name="password" id="password"></td>
</tr>
<tr>
<td>图形验证码</td>
<td><input type="text" name="imageCode" id="imageCode">
<img src="/code/image" alt="">
</td>
</tr>
<tr>
<td colspan="2"><input type="checkbox" name="remember-me" id="remember_me" checked/>记住我</td>
</tr>
<tr>
<td colspan="2">
<button type="submit">提交</button>
</td>
</tr>
</table>
</form>
</body>
</html>
3.2 后台
import com.tdt.security.browser.authentication.TdtAuthenticationFailureHandler;
import com.tdt.security.browser.authentication.TdtAuthenticationSuccessHandler;
import com.tdt.security.properties.SecurityProperties;
import com.tdt.security.validate.code.ValidateCodeFilter;
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.core.userdetails.UserDetailsService;
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;
/**
* @Project: tdt-security
* @ClassName: BrowserSecurityConfig
* @Description: 浏览器配置类
* @Author: Mr.superbeyone
* @Create: 2018-11-28 16:44
**/
@Configuration
public class BrowserSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
SecurityProperties securityProperties;
@Autowired
TdtAuthenticationSuccessHandler tdtAuthenticationSuccessHandler;
@Autowired
TdtAuthenticationFailureHandler tdtAuthenticationFailureHandler;
@Autowired
DataSource dataSource;
@Autowired
UserDetailsService userDetailsService;
@Bean
public PasswordEncoder BCryptPasswordEncoder() {
return new BCryptPasswordEncoder();
}
//记住我功能 start
@Bean
public PersistentTokenRepository persistentTokenRepository(){
JdbcTokenRepositoryImpl tokenRepository = new JdbcTokenRepositoryImpl();
tokenRepository.setDataSource(dataSource);
// tokenRepository.setCreateTableOnStartup(true);//第一次启动时放开,会自动生成persistent_logins表
//"create table persistent_logins (username varchar(64) not null, series varchar(64) primary key, "
// + "token varchar(64) not null, last_used timestamp not null)"
return tokenRepository;
}
//记住我功能 end
@Override
protected void configure(HttpSecurity http) throws Exception {
ValidateCodeFilter validateCodeFilter = new ValidateCodeFilter();
validateCodeFilter.setAuthenticationFailureHandler(tdtAuthenticationFailureHandler);
validateCodeFilter.setSecurityProperties(securityProperties);
validateCodeFilter.afterPropertiesSet();
http.addFilterBefore(validateCodeFilter, UsernamePasswordAuthenticationFilter.class)
.formLogin() //想用默认的HttpBasic登录使用 http.httpBasic()
.loginPage("/authentication/require")
.loginProcessingUrl("/authentication/form")
.successHandler(tdtAuthenticationSuccessHandler)
.failureHandler(tdtAuthenticationFailureHandler)
.and()
.rememberMe()//配置记住我
.tokenRepository(persistentTokenRepository())
.tokenValiditySeconds(securityProperties.getBrowser().getRememberMeSeconds())//参数为整形数值,在此只是封装了一下
.userDetailsService(userDetailsService)
.and()
.authorizeRequests()//下面的配置都是授权配置
.antMatchers("/authentication/require",
securityProperties.getBrowser().getLoginPage(),
"/code/image")
.permitAll()
.anyRequest()//任何请求
.authenticated()//都需要身份认证
.and()
.csrf().disable();//关闭跨站请求防护
}
}
注:展示的代码只是实现思想,完成代码结构,移步GitHub 源码地址
4. 源码追踪
4.1 第一次登录
UsernamePasswordAuthenticationFilter
AbstractAuthenticationProcessingFilter
PersistentTokenBasedRememberMeServices
4.2 记住我之后,第二次登录
RememberMeAuthenticationFilter
PersistentTokenBasedRememberMeServices
- 经过一系列检查之后
RememberMeAuthenticationFilter
github 源码地址