自动登录

n天内免登陆

实现原理

Spring Security的自动登录实现原理:

  1. 生成一串加密串,作为cookie存入客户浏览器
  2. 将加密串和其对应的用户信息字符串存入数据库

当用户再次访问时,获取到cookie中的加密串,到数据库中进行比对,如果查询到对应信息,就认证成功自动登录。

第一次登录的时序图:

浏览器->UsernamePasswordAuthenticationFilter: 认证请求 UsernamePasswordAuthenticationFilter->RememberMeService(TokenRepository): 认证成功 RememberMeService(TokenRepository)->浏览器: 将Token写入浏览器Cookie RememberMeService(TokenRepository)->DB: 将Token写入数据库

第一次登录成功后,后续自动登录时序图:

浏览器->RememberMeAuthenticationFilter: 服务请求 RememberMeAuthenticationFilter->RememberMeService(TokenRepository): 读取Cookie中的Token RememberMeService(TokenRepository)->DB: 查找Token RememberMeService(TokenRepository)->UserDetailsService: 自动登录

功能实现

  1. 创建相关数据库表

    建表语句位于 JdbcTokenRepositoryImpl类中,也可以让Spring Security自动创建

  1. create table persistent_logins (
  2. username varchar(64) not null,
  3. series varchar(64) primary key,
  4. token varchar(64) not null,
  5. last_used timestamp not null
  6. );
  1. 编写配置类,注入数据源,配置操作数据库对象 ```java @Autowired private DataSource dataSource;

// 将tokenRepository加入Spring容器 @Bean public PersistentTokenRepository persistentTokenRepository() { JdbcTokenRepositoryImpl repository = new JdbcTokenRepositoryImpl(); repository.setDataSource(dataSource); // 注入数据源 // repository.setCreateTableOnStartup(true); // 自动创建存储Token的表 return repository; }

  1. 3.
  2. 在自定义的`WebSecurityConfigurerAdapter`子类中,`configure(HttpSecurity http)`方法中加入Token配置
  3. ```java
  4. @Override
  5. protected void configure(HttpSecurity http) throws Exception {
  6. http.formLogin() // 自定义登录页面
  7. //........
  8. // 设置“记住我”
  9. .and().rememberMe().tokenRepository(persistentTokenRepository())
  10. .tokenValiditySeconds(60) // 设置Token的有效时长
  11. .userDetailsService(userDetailsService) // 配置操作数据库的UserDetailsService
  12. //........
  13. }
  1. 在登录页面添加”记住我”复选框按钮
    <form action="/user/login" method="post">
     用户名:<input type="text" name="username">
     <br>
     密码:<input type="password" name="password">
     <br>
     <!-- 该name必须为 remember-me, 否则Spring Security不识别 -->
     <input type="checkbox" name="remember-me" title="记住密码">记住我
     <br>
     <input type="submit" value="login">
    </form>