zoukankan      html  css  js  c++  java
  • Spring Security -- 添加记住我功能(转载)

    在网站的登录页面中,记住我选项是一个很常见的功能,勾选记住我后在一段时间内,用户无需进行登录操作就可以访问系统资源。在Spring Security中添加记住我功能很简单,大致过程是:当用户勾选了记住我选项并登录成功后,Spring Security会生成一个token标识,然后将该token标识持久化到数据库,并且生成一个与该token相对应的cookie返回给浏览器。当用户过段时间再次访问系统时,如果该cookie没有过期,Spring Security便会根据cookie包含的信息从数据库中获取相应的token信息,然后帮用户自动完成登录操作。

    一、token持久化

    Spring Security的记住我功能的实现需要使用数据库来持久化token。我们在上一节Spring Security添加图形验证码的基础上来添加记住我的功能。

    1、添加依赖

    在application.yml中添加数据源配置:

    spring:
      datasource:
        driver-class-name: com.mysql.jdbc.Driver
        url: jdbc:mysql://127.0.0.1:3306/goldwind?useUnicode=yes&characterEncoding=UTF-8&useSSL=false
        username: root
        password: 123456aa

    添加数据库依赖:

     <!--   mysql -->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-jdbc</artifactId>
            </dependency>
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <version>5.1.47</version>
            </dependency>

    2、配置bean

    然后我们在BeanConfig中配置个token持久化对象:

    package com.goldwind.config;
    
    import com.fasterxml.jackson.databind.ObjectMapper;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
    import org.springframework.security.crypto.password.PasswordEncoder;
    import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl;
    import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;
    
    import javax.sql.DataSource;
    
    
    /**
     * @Author: zy
     * @Description: 定义一些bean
     * @Date: 2020-2-9
     */
    @Configuration
    public class BeanConfig {
    
        /**
         * 从配置文件注入
         */
        @Autowired
        private DataSource dataSource;
    
        /**
         * token持久化对象
         * @return
         */
        @Bean
        public PersistentTokenRepository persistentTokenRepository(){
            JdbcTokenRepositoryImpl jdbcTokenRepositoryImpl = new JdbcTokenRepositoryImpl();
            jdbcTokenRepositoryImpl.setDataSource(dataSource);
            jdbcTokenRepositoryImpl.setCreateTableOnStartup(false);
            return jdbcTokenRepositoryImpl;
        }
        
        ...
    }

    PersistentTokenRepository为一个接口类,这里我们用的是数据库持久化,所以实例用的是PersistentTokenRepository的实现类JdbcTokenRepositoryImpl。

    JdbcTokenRepositoryImpl需要指定数据源,所以我们将配置好的数据源对象DataSource注入进来并配置到JdbcTokenRepositoryImpl的dataSource属性中。createTableOnStartup属性用于是否启动项目时创建保存token信息的数据表,这里设置为false,我们自己手动创建。

    查看JdbcTokenRepositoryImpl的源码,可以看到其包含了一个CREATE_TABLE_SQL属性:

        /** Default SQL for creating the database table to store the tokens */
        public static final String CREATE_TABLE_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)";
        /** The default SQL used by the <tt>getTokenBySeries</tt> query */
        public static final String DEF_TOKEN_BY_SERIES_SQL = "select username,series,token,last_used from persistent_logins where series = ?";
        /** The default SQL used by <tt>createNewToken</tt> */
        public static final String DEF_INSERT_TOKEN_SQL = "insert into persistent_logins (username, series, token, last_used) values(?,?,?,?)";
        /** The default SQL used by <tt>updateToken</tt> */
        public static final String DEF_UPDATE_TOKEN_SQL = "update persistent_logins set token = ?, last_used = ? where series = ?";
        /** The default SQL used by <tt>removeUserTokens</tt> */
        public static final String DEF_REMOVE_USER_TOKENS_SQL = "delete from persistent_logins where username = ?";

    这个其实就是用于保存token对象数据表的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
    )

    二、修改登录页

    完成上述配置后,我们稍微改造下登录页,加入记住我的勾选选项:

    <input type="checkbox" name="remember-me"/> 记住我
    <br>

    其中name属性必须为remember-me.

    三、配置生效

    最后我们需要在Spring Security的认证流程中启用记住我的功能,在BrowserSecurityConfig的configure方法中开启记住我功能:

        @Autowired
        private PersistentTokenRepository persistentTokenRepository;
    
        @Autowired
        private CustomUserDetailService userDetailService;
    
        /**
         * 配置拦截请求资源
         * @param http:HTTP请求安全处理
         * @throws Exception
         */
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http.addFilterBefore(validateCodeFilter, UsernamePasswordAuthenticationFilter.class) // 添加验证码校验过滤器
                    .authorizeRequests()    // 授权配置
                    .antMatchers("/code/image")
                    .permitAll()       // 无需认证的请求路径
                    .anyRequest()       // 任何请求
                    .authenticated()    //都需要身份认证
                    .and()
                    .formLogin()         // 或者httpBasic()
                    .loginPage("/login")  // 指定登录页的路径
                    .loginProcessingUrl("/login")  // 指定自定义form表单请求的路径
                    .successHandler(authenticationSucessHandler)    // 处理登录成功
                    .failureHandler(authenticationFailureHandler) // 处理登录失败
                    // 必须允许所有用户访问我们的登录页(例如未验证的用户,否则验证流程就会进入死循环)
                    // 这个formLogin().permitAll()方法允许所有用户基于表单登录访问/login这个page。
                    .permitAll()
                    .and()
                    .rememberMe()
                    .tokenRepository(persistentTokenRepository)  // 配置 token 持久化仓库
                    .tokenValiditySeconds(3600)      // remember 过期时间,单为秒
                    .userDetailsService(userDetailService)   // 处理自动登录逻辑
                    .and()
                    .logout()
                    .permitAll()
                    .and()
                    //默认都会产生一个hiden标签 里面有安全相关的验证 防止请求伪造 这边我们暂时不需要 可禁用掉
                    .csrf().disable();
        }

    rememberMe()用于开启记住我功能;tokenRepository(persistentTokenRepository())用于指定token持久化方法;tokenValiditySeconds配置了token的有效时长,单为为秒;userDetailsService(userDetailService)用于处理通过token对象自动登录,这里为我们自定义的UserDetailsService接口实现。

    配置好后,重启项目,登录页面如下所示:

    勾选并成功登录后,可以看到网页多了个remember-me的cookie对象:

     查看数据库表persistent_logins:

    可以看到token信息已经成功持久化了,并且浏览器也成功生成了相应的cookie。在cookie未失效之前,无论是重开浏览器或者重启项目,用户都无需再次登录就可以访问系统资源了。

    参考文章:
    [1] Spring Security添加记住我功能(转载)

  • 相关阅读:
    Codeforces 547D. Mike and Fish 题解
    Codeforces 521E. Cycling City 题解
    Codeforces 585E. Present for Vitalik the Philatelist 题解
    Codeforces 605E. Intergalaxy Trips 题解
    AGC033D
    第3次作业:卷积神经网络
    Linux下如何编写go语言程序实现菲波拉契数列
    C语言常见典型错误汇总(助教)
    第一次作业:深度学习基础
    数论复习_欧几里得算法与扩展欧几里得算法
  • 原文地址:https://www.cnblogs.com/zyly/p/12287653.html
Copyright © 2011-2022 走看看