原理
在用户发送认证请求之后,或调用我们之前说过的usernamePasswordAuthenticationFilter这个过滤器,认证成功之后会调用一个RemeberMeService服务;负责针对每一用户生成一个Token,然后将token写入到浏览器的Cookie里面,同时会使用:TokenRepository将这个token写入数据库中。将Token写入数据库时候,同时会把用户认证成功的用户名一并写入数据库(此时用户名和token是一一对应的)中因为我们是在用户认证成功之后做的,所以会将用户信息写入,下次用户访问的时候就不需要再次登录了。当用户下次请求的时候会经过过滤器链中的RemeberMeAuthenticationFilter(这个过滤器作用就是读取cookie中token)然后交给RemeberMeService,RemeberMeService通过TokenRepository到数据库去查询这个Token数据库里面有没有记录。如果有记录就去除用户名,取出用户名之后,就会去调用UserDetailsService,获取用户信息,然后把获取的当前用户信息放到SecurityContext里面。这样就把用户登录上了。
RemeberMeAuthenticationFilter在我们的过滤器链中绿色过滤器中,他是在倒数第二个位置。前面是其他的认证,其他的认证都没法认证用户信息的时候RemeberMeAuthenticationFilter尝试去做认证。
实现
前端
配置TokenRepository
配置TokenRepository读取数据库,SecurityConfig类中配置
BrowserSecurityConfig类中
- 配置PersistentTokenRepository 读写数据库
- 配置token过期的秒数
- 验证token,配置UserDetailsService的实现类
@Configuration public class BrowserSecurityConfigOld extends WebSecurityConfigurerAdapter { //security配置类 @Autowired private SecurityProperties securityProperties; @Autowired private MyAuthenticationFailureHandler myAuthenticationFailureHandler; @Autowired private MyAuthenticationSuccessHandler myAuthenticationSuccessHandler; @Autowired private DataSource dataSource;//yml文件中,spring.datasource @Autowired private UserDetailsService userDetailsService; //实现UserDetailsServiceImpl @Bean public PersistentTokenRepository persistentTokenRepository(){ JdbcTokenRepositoryImpl jdbcTokenRepository = new JdbcTokenRepositoryImpl(); jdbcTokenRepository.setDataSource(dataSource);//配置数据源 //在启动的时候会自动创建存放记住我的表(persistent_logins),如果存在会报错(手动创建) //jdbcTokenRepository.setCreateTableOnStartup(true); return jdbcTokenRepository; } @Override protected void configure(HttpSecurity http) throws Exception { // 图片验证码过滤器 //创建验证码过滤器,验证器使用自定义错误处理 ValidateCodeFilter validateCodeFilter = new ValidateCodeFilter(/*myAuthenticationFailureHandler*/); //配置验证码过滤url //validateCodeFilter.setSecurityProperties(securityProperties); validateCodeFilter.afterPropertiesSet(); //加入过滤器链,在UsernamePasswordAuthenticationFilter之前 http.addFilterBefore(validateCodeFilter, UsernamePasswordAuthenticationFilter.class) .addFilterBefore(smsCodeFilter, UsernamePasswordAuthenticationFilter.class) .formLogin() //表单登陆认证方法,浏览器跳转到specurity默认登陆页面 //http.httpBasic()//浏览器弹出登陆对话框登陆认证方式 //.loginPage("/login.html")//自定义登陆页面 .loginPage("/authentication/require")//自定义登陆url .loginProcessingUrl("/authentication/form")//用户登陆提交接口 .successHandler(myAuthenticationSuccessHandler) .failureHandler(myAuthenticationFailureHandler) .and() .rememberMe() .tokenRepository(persistentTokenRepository())//配置remeberMe的token操作 .tokenValiditySeconds(securityProperties.getBrowser().getRememberMeSeconds()) // rememberME 有效期 .userDetailsService(userDetailsService) //验证记得我的token .and() .authorizeRequests() ////设置请求符合访问资源的权限 .antMatchers(securityProperties.getBrowser().getLoginPage(),"/myLogin.html","/code/*","/authentication/require","/authentication/mobile")//匹配器 .permitAll()//访问这两个页面不需要认证 .anyRequest().authenticated() //对任何请求都要登陆认证后才能访问 .and() .csrf().disable()//关闭跨域伪造关闭 .apply(smsCodeAuthenticationSecurityConfig); } @Bean public PasswordEncoder passwordEncoder() { //return NoOpPasswordEncoder.getInstance(); //已弃用 return new BCryptPasswordEncoder(); } }
数据库表
JdbcTokenRepositoryImpl 类中有一个变量
创建表有两种思路:
- 拷贝出sql语句,手动创建
CREATE TABLE persistent_logins (
username VARCHAR (64) NOT NULL,
series VARCHAR (64) PRIMARY KEY,
token VARCHAR (64) NOT NULL,
last_used datetime NOT NULL
);
2. jdbcTokenRepository.setCreateTableOnStartup(true);
在启动的时候会自动创建存放记住我的表(persistent_logins),如果存在会报错(手动创建)
标签:记得,数据库,用户,private,认证,token,过滤器,SpringSecurity From: https://www.cnblogs.com/wangzhilei-src/p/17976744