RememberMe的实现一定离不开Token的持久化存储。来看看使用Security应该怎么用RememberMe功能
RememberMe实现的两个模式
Security中有着两个实现RememberMe功能的实现类,但是都离不开持久化Token。
- AbstractRememberMeServices的实现类
-
PersistentTokenBasedRememberMeServices
服务端或数据库保存Cookie- 其中
tokenRepository
属性时存储的方案:-
InMemoryTokenRepositoryImpl
存储到内存中(Map) -
JdbcTokenRepositoryImpl
存储到数据库中
-
- 其中
-
TokenBasedRememberMeServices
客户端保存Cookie- 通过对Token串的加密和解密进行认证
-
Token持久化到数据库
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private DataSource dataSource;
@Autowired
public UserDetailsService userDetailsService;
@Bean
public PasswordEncoder passwordEncoder () {
return new BCryptPasswordEncoder();
}
/**
* PersistentTokenRepository持久化Token实现类:
* 1. JdbcTokenRepository
* 2. InMemoryTokenRepository
* @return Remember-Me的TokenRepository
*/
@Bean
public PersistentTokenRepository persistentTokenRepository() {
JdbcTokenRepositoryImpl jdbcTokenRepository = new JdbcTokenRepositoryImpl();
// 设置JdbcDaoSupport对象中的JdbcTemplate所需要的DataSource对象。
jdbcTokenRepository.setDataSource(dataSource);
// 自动创建表结构,在没有表的情况下,会自动生成persistent_tokens表
// jdbcTokenRepository.setCreateTableOnStartup(true);
return jdbcTokenRepository;
}
// 无需自己创建。
// security自动根据是否存在tokenRepository来创建PersistentTokenBasedRememberMeServices或者TokenBasedRememberMeServices
//
// @Bean
// public RememberMeServices rememberMeServices() {
// PersistentTokenBasedRememberMeServices persistentTokenBasedRememberMeServices = new PersistentTokenBasedRememberMeServices("yyl", userDetailsService, persistentTokenRepository());
// // 持久化token有效期时长
// persistentTokenBasedRememberMeServices.setTokenValiditySeconds(AbstractRememberMeServices.TWO_WEEKS_S);
// return persistentTokenBasedRememberMeServices;
// }
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// auth.userDetailsService(userDetailsService).passwordEncoder(new BCryptPasswordEncoder());
auth.userDetailsService(userDetailsService);
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.exceptionHandling().accessDeniedPage("/test/unAuthority");
http.formLogin() // 自定义登录配置
.loginPage("/login.html") // 登录页url
.loginProcessingUrl("/user/login") // 验证登录的url
.defaultSuccessUrl("/test/index.html") // 默认登录成功,将重定向到的url
// .failureUrl("/test/loginFailed.html").permitAll() // 默认登录失败,将重定向到的url
.permitAll()
.and().authorizeRequests()
.antMatchers("/", "/test/hello", "/user/login", "/test/current", "/test/sessionInvalidate").permitAll() // 设置哪些路径可以直接访问,不需要认证
.antMatchers("/test/managepage.html").hasAuthority("admin,manage")
.antMatchers("/test/anyRole").hasAnyRole("zs", "ls")
.anyRequest().authenticated()
.and().csrf()
.disable();
// 退出之后,跳转到LogoutSuccess需要权限才能进去。 permitAll将前面的地址设置为不需要权限就可以进去。 与permitAll相对应的是authenticated
http.logout().logoutUrl("/logout").logoutSuccessUrl("/test/logoutSuccess").permitAll();
// 无需自己创建。
// security自动根据是否存在tokenRepository来创建PersistentTokenBasedRememberMeServices或者TokenBasedRememberMeServices
// http.rememberMe().rememberMeServices(rememberMeServices());
http.rememberMe().tokenRepository(persistentTokenRepository()).userDetailsService(userDetailsService)
// .tokenValiditySeconds(AbstractRememberMeServices.TWO_WEEKS_S);
.tokenValiditySeconds(30);
}