目录
  • 简介
  • 思维逻辑
  • 配置和测试
    • 数据库创建
    • 配置类注入数据源,配置操作数据库对象
    • 配置config(HttpSecurity)
    • 页面增加记住我选项
    • 测试
  • 注意事项
    • 原理分析
      • 代码下载

        简介

        在一般的网站中,比如Bilibili。当用户登录成功后,关闭浏览器后,下次重新进入网站,可以自动登录。

        本次就来探究如何实现这种自动登录记住我的功能。

        思维逻辑

        需要实现记住我的功能操作,需要保证具体的实现方式,接下来就来梳理下。

        首先,在Security框架中,针对记住我的功能实现,Security框架本身对其做了一定的封装,其实现原理为:

        • 浏览器:cookie中存储加密后的数据串
        • 数据库:MySQL等数据库中存储加密后的数据串用户基本信息数据。

        当认证器中,根据客户端传递的cookie值,查询服务器,符合用户基本信息,则自动放行。

        配置和测试

        数据库创建

        本质上是不要创建的,Security框架针对记住我功能的实现,会在数据库不存在表时,org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl自动创建一个persistent_logins表。

        如果想手动创建,可以执行下列sql进行表的创建:

        CREATE TABLE persistent_logins (
        username VARCHAR ( 64 ) NOT NULL,
        series VARCHAR ( 64 ) PRIMARY KEY,
        token VARCHAR ( 64 ) NOT NULL,
        last_used TIMESTAMP NOT NULL 
        );

        配置类注入数据源,配置操作数据库对象

        import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl;
        import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;
        import javax.sql.DataSource;
        
        /**
           * 注入数据源(记住我)
           */
          @Autowired
          private DataSource dataSource;
          /**
           * 配置操作数据库对象
           * @return
          @Bean
          public PersistentTokenRepository persistentTokenRepository(){
              JdbcTokenRepositoryImpl jdbcTokenRepository = new JdbcTokenRepositoryImpl();
              jdbcTokenRepository.setDataSource(dataSource);
              jdbcTokenRepository.setCreateTableOnStartup(true); // 如果没有配置记住我的数据表,则自动生成
              return jdbcTokenRepository;
          }

        配置config(HttpSecurity)

        .and()
        .rememberMe().tokenRepository(persistentTokenRepository()) // 配置记住我的功能,同时增加查询数据库 cookie 值
        .tokenValiditySeconds(60)  // 设置cookie的有效时间(秒为单位)
        .userDetailsService(mySecurityService) // 查询数据库
        

        页面增加记住我选项

        <!DOCTYPE html>
        <html lang="en">
        <head>
            <meta charset="UTF-8">
            <title>Title</title>
        </head>
        <body>
            <form action="/user/login" method="post">
                用户名:<input type="text" name="username" /><br/>
                密码:<input type="text" name="password" /><br/>
                <input type="checkbox" name="remember-me" title="记住我" />自动登录<br/>
                <input type="submit" value="login" /><br/>
            </form>
        </body>
        </html>
        

        主要代码为:

        <input type="checkbox" name="remember-me" title="记住我" />自动登录<br/>
        

        【注意:】name="remember-me" 这是固定写法,否则无法识别!

        测试

        重启服务器,请求需要被认证的url:

        http://localhost/login.html

        关闭浏览器,重新打开,重新请求:
        http://localhost/loginSuccess.html

        注意事项

        由于数据库本身未创建 persistent_logins表,只是在配置类中申明创建表

        此时数据库中,可以看到已存在表信息:

        此处需要注意的是,如果配置了自动创建表,如果已存在指定的表,启动会报错!

        原理分析


        1、浏览器请求服务器时,会先经过UsernamePasswordAuthenticationFilter进行认证操作
        2、如果UsernamePasswordAuthenticationFilter认证成功,会调用其父类 AbstractAuthenticationProcessingFilter中的doFilter方法。
        3、最终执行this.successfulAuthentication(request, response, chain, authResult)

        org.springframework.security.web.authentication.rememberme.AbstractRememberMeServices中的loginSuccess方法。

        然后在org.springframework.security.web.authentication.rememberme.PersistentTokenBasedRememberMeServices#onLoginSuccess中做以下操作:

        4、将生成的新的token信息,存储于数据表中,并且也存储在浏览器 cookie 中
        5、当浏览器关闭,下次登录时,会根据之前设定的remember-me信息,在org.springframework.security.web.authentication.rememberme.RememberMeAuthenticationFilter中对其验证!

        代码下载

        springboot-security-09-rememberMe

        gitee 代码下载