上一篇:https://lawsssscat.blog.csdn.net/article/details/105321389

前面的代码下载:https://github.com/LawssssCat/v-security/tree/v2.3

三部分

  • 记住我功能基本原理
  • 记住我功能具体实现
  • 记住我功能Spring Security源码解析

记住我功能基本原理

  • 当用户登录时,发起认证请求给 UsernamePasswordAuthenticationFilter

  • 当认证成功,会调用 RememberMeService 服务

  • RememberMeService 服务会生成一个 Token
    首先,会把 Token写入到浏览器的 Cookie 里面。
    然后, RememberMeService 里面有 TokenRepository
    RememberMeService 会使用 TokenRepository 把 Token 写入到数据库里面


<mark>另外一个会话</mark>

  • 当浏览器携带有 TokenCookie 请求服务
    会来到 RememberMeAuthenticationFilter

  • RememberMeAuthenticationFilter 会读取请求中的 Cookie
    并取出 Token 部分交给 RememberMeService

  • RememberMeService 借助 TokenRepository 从数据库中查找有没有对应的 Token 记录
    如果有对应的 Token 记录,就返回对应的用户信息(UserDetails),并交给 UserDetailsService

  • UserDetailsService 就用 UserDetails 获取用户信息,并放入 SecurityContext 里面,这样就把用户登录上了

RememberMeAuthenticationFilter 的位置,是当用户密码,httpBasic认证都没用时,起作用

记住我功能具体实现

登录界面添加按钮

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<h2>登录22222222222</h2>
<!--路径是我们自定义的,默认值为/login,在UsernamePasswordAuthenticationFilter中定义-->
<form method="post" action="/authentication/form">
    username: <input type="text" name="username"><br>
    pawssword: <input type="text" name="password"><br>
    图形验证码:<input type="text" name="imageCode"> <img src="/code/image?width=600"><br>
    <input type="checkbox" value="true" name="remember-me">记住我<br>
    <input type="submit" value="登录">
</form>

</body>
</html>

配置 TokenRepository
在 v-security-browser 的配置类里面配置

在 BrowserSecurityConfig 里面添加代码

    @Autowired
    private UserDetailsService userDetailsService ;
    
    @Autowired
    private DataSource dataSource;

    /** * @return RememberMe 功能的 Repository */
    @Bean
    public PersistentTokenRepository persistentTokenRepository() {
        // 连接数据库的实现类,还有一个实现类时存内存的InMemoryTokenRepositoryImpl
        JdbcTokenRepositoryImpl tokenRepository = new JdbcTokenRepositoryImpl();
        // 配置数据源
        tokenRepository.setDataSource(dataSource);
        // 在启动数据库时创建存储token的表
        tokenRepository.setCreateTableOnStartup(true);
        return tokenRepository;
    }

配置记住我生效时间

在 BrowserProperties 里面配置


配置数据源信息(很早前在v-security-demo里面就配过了)

spring:
  datasource:
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://vdb.cn:3306/vsdb?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&useSSL=false
    username: root
    password: root

配置类中整合前面所有配置

.and()
// 记住我配置
.rememberMe()
.tokenRepository(persistentTokenRepository())
.tokenValiditySeconds(securityProperties.getBrowser().getRememberMeSeconds())
.userDetailsService(userDetailsService)

启动系统

看数据库

可以看到多了一张表

这是因为 tokenRepository.setCreateTableOnStartup(true); 这句代码起作用
当里面为 true 时,项目启动,JdbcTokenRepositoryImpl就会执行它内部写死的一段建表代码(下图)

<mark>再次启动时,要注掉下面代码,因为表已存在,无法再创建</mark>

登录

访问:http://localhost:8080/login2.html
<mark>记住记住我</mark>(下图)


访问:http://localhost:8080/user
访问没问题(下图)

这时去看数据库,会在表persistent_logins中多出一条数据

这时去看浏览器的application的cookie里,也能看到 remember-me 的值

删除cookie里的 JSESSIONID,还是可以再次访问 http://localhost:8080/user

这就是下面一个cokkie : remember-me 的作用
(注意 remember-me 中有过期时间,当过期时间没到,关闭浏览器,remember-me会被序列化到硬盘,当再次打开浏览器时被反序列化。因此,可以看作,在过期时间前,会在一直存在于浏览器中,并且伴随请求被发送到服务器)

done~

如果返回提示:“content”: “验证码的值不能为空”

进行下面注释

记住我功能 Spring Security 源码解析

# 登录

<mark>在 UsernamePasswordAuthenticationFilter 的 attemptAuthentication 中设置断点</mark>(下图)

重新登录 http://localhost:8080/login2.html



它是被 AbstractAuthenticationProcessingFilter 调用 (下图)

当一切成功 会进入 successfulAuthentication 方法(下图)

successfulAuthentication 里面有 rememberMeServices 的调用

调用方法 onLoginSuccess


# 使用cookie中的token

在 RememberMeAuthenticationFilter 的 doFilter 中添加断点

删除cookie中的 JSESSIONID,重新访问 http://localhost:8080/user


processAutoLoginCookie 方法就是访问数据库对照 token 获取 UserDetails的


最终用 getUserDetailsService 获取 UserDetails

前面的代码下载:https://github.com/LawssssCat/v-security/tree/v2.4

done~