zoukankan      html  css  js  c++  java
  • 【Spring-Security】Re07 持久化的记住我

    Security记住我功能底层实现依赖于SpringJDBC组件,如果有持久层框架的话,就由持久层框架实现

    演示案例的选型,MysqlJdbc + MybatisStarter

    <dependency>
        <groupId>org.mybatis.spring.boot</groupId>
        <artifactId>mybatis-spring-boot-starter</artifactId>
        <version>2.1.2</version>
    </dependency>
    
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
    </dependency>

    如果是不同的数据库类型,就更换不同的驱动,链接参数的要求是一致的

    数据源没有配置,默认使用了自带的Hikari

    spring:
      datasource:
        driver-class-name: com.mysql.cj.jdbc.Driver
        url: jdbc:mysql://localhost:3308/spring-security?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=UTF-8&useSSL=true
        username: root
        password: 123456

    配置类的更改:

    package cn.zeal4j.configuration;
    
    import cn.zeal4j.handler.CustomAccessDeniedHandler;
    import cn.zeal4j.handler.FarsAuthenticationFailureHandler;
    import cn.zeal4j.handler.FarsAuthenticationSuccessHandler;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.beans.factory.annotation.Qualifier;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.http.HttpMethod;
    import org.springframework.security.config.annotation.web.builders.HttpSecurity;
    import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
    import org.springframework.security.core.parameters.P;
    import org.springframework.security.core.userdetails.UserDetails;
    import org.springframework.security.core.userdetails.UserDetailsService;
    import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
    import org.springframework.security.crypto.password.PasswordEncoder;
    import org.springframework.security.web.access.AccessDeniedHandler;
    import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl;
    import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;
    
    import javax.sql.DataSource;
    
    /**
     * @author Administrator
     * @file IntelliJ IDEA Spring-Security-Tutorial
     * @create 2020 09 27 21:55
     */
    @Configuration
    public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
    
        @Autowired
        private AccessDeniedHandler accessDeniedHandler;
        @Qualifier("userDetailsServiceImpl")
        @Autowired
        private UserDetailsService userDetailsService;
        @Autowired
        private DataSource dataSource;
        @Autowired
        private PersistentTokenRepository persistentTokenRepository;
    
        @Bean
        public PersistentTokenRepository getPersistentTokenRepository() {
            JdbcTokenRepositoryImpl jdbcTokenRepository = new JdbcTokenRepositoryImpl();
            jdbcTokenRepository.setDataSource(dataSource); // 数据源注入
            jdbcTokenRepository.setCreateTableOnStartup(true); // 由Security完成Token表的创建
            return jdbcTokenRepository;
        }
    
        @Bean
        public PasswordEncoder getPasswordEncoder() {
            return new BCryptPasswordEncoder();
        }
    
        @Override
        protected void configure(HttpSecurity httpSecurity) throws Exception {
            httpSecurity.formLogin(). // 设置登陆行为方式为表单登陆
                    // 登陆请求参数设置
                    usernameParameter("username").
                    passwordParameter("password").
                    
                    loginPage("/login.html"). // 设置登陆页面URL路径
                    loginProcessingUrl("/login.action"). // 设置表单提交URL路径
                    
                    successForwardUrl("/main.page"). // 设置认证成功跳转URL路径 POST请求
                    failureForwardUrl("/error.page");  // 设置认证失败跳转URL路径 POST请求
                    
                    //  successHandler(new FarsAuthenticationSuccessHandler("https://www.acfun.cn/")). // 使用自定义的重定向登陆
                    //  failureHandler(new FarsAuthenticationFailureHandler("/error.html")).; // 跨域处理,不需要跳转了
    
            httpSecurity.authorizeRequests().
                    regexMatchers(HttpMethod.POST, "正则表达式").permitAll(). // 还可以对符合正则表达式的请求方式进行要求,这个属性使用来制定请求的方式
                    
                    antMatchers("/**/*.js", "/**/*.css", "/**/images/*.*").permitAll(). // 静态资源放行
                    
                    antMatchers("/login.html").permitAll(). // 登陆页面允许任意访问
                    antMatchers("/error.html").permitAll(). // 失败跳转后重定向的页面也需要被允许访问
                    antMatchers("/admin.page").hasAnyAuthority("admin").
                    
                    /*antMatchers("/vip-01.page").hasAnyAuthority("vip-01").*/
                    antMatchers("/vip-01.page").hasRole("vip-01").
                    antMatchers("/ip.page").hasIpAddress("192.168.43.180").
                    
                    // mvcMatchers("/main.page").servletPath("/xxx").permitAll(). // mvcMatchers资源放行匹配
                    // antMatchers("/xxx/main.page").permitAll(). // 或者多写MSP的前缀
                    
                    anyRequest().authenticated(); // 其他请求均需要被授权访问
                    // anyRequest().access("@customServiceImpl.hasPermission(request, authentication)"); // 自定义Access配置
    
            // CSRF攻击拦截关闭
            httpSecurity.csrf().disable();
            httpSecurity.exceptionHandling().accessDeniedHandler(accessDeniedHandler);
    
    
            // 记住我
            httpSecurity.rememberMe().userDetailsService(userDetailsService).tokenRepository(persistentTokenRepository);
        }
    }

    在之前的登陆页面中编写记住我选项框:

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
        <style type="text/css">
            h3,p {
                text-align: center;
            }
        </style>
    </head>
    <body>
        <h3>custom login page</h3>
        <form method="post" action="/login.action" >
            <p>username: <input type="text" name="username"></p>
            <p>password: <input type="password" name="password"></p>
            <p>rememberMe: <input type="checkbox" name="remember-me" value="true"></p>
            <p><input type="submit" value="login"></p>
        </form>
    </body>
    </html>

    现在启动项目,会发现数据库多了一张persistent_logins表

    登陆访问勾选记住我,会插入用户的令牌和信息

    这时候关闭浏览器再打开,不需要验证就可以直接到首页了

    持续时间是永久的,因为Token表的记录一直存在,除非记录被删除

    或者调用HttpSecurity的方法,设置失效时间:

    package cn.zeal4j.configuration;
    
    import cn.zeal4j.handler.CustomAccessDeniedHandler;
    import cn.zeal4j.handler.FarsAuthenticationFailureHandler;
    import cn.zeal4j.handler.FarsAuthenticationSuccessHandler;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.beans.factory.annotation.Qualifier;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.http.HttpMethod;
    import org.springframework.security.config.annotation.web.builders.HttpSecurity;
    import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
    import org.springframework.security.core.parameters.P;
    import org.springframework.security.core.userdetails.UserDetails;
    import org.springframework.security.core.userdetails.UserDetailsService;
    import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
    import org.springframework.security.crypto.password.PasswordEncoder;
    import org.springframework.security.web.access.AccessDeniedHandler;
    import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl;
    import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;
    
    import javax.sql.DataSource;
    
    /**
     * @author Administrator
     * @file IntelliJ IDEA Spring-Security-Tutorial
     * @create 2020 09 27 21:55
     */
    @Configuration
    public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
    
        @Autowired
        private AccessDeniedHandler accessDeniedHandler;
        @Qualifier("userDetailsServiceImpl")
        @Autowired
        private UserDetailsService userDetailsService;
        @Autowired
        private DataSource dataSource;
        @Autowired
        private PersistentTokenRepository persistentTokenRepository;
    
        @Bean
        public PersistentTokenRepository getPersistentTokenRepository() {
            JdbcTokenRepositoryImpl jdbcTokenRepository = new JdbcTokenRepositoryImpl();
            jdbcTokenRepository.setDataSource(dataSource); // 数据源注入
            jdbcTokenRepository.setCreateTableOnStartup(true); // 由Security完成Token表的创建
            return jdbcTokenRepository;
        }
    
        @Bean
        public PasswordEncoder getPasswordEncoder() {
            return new BCryptPasswordEncoder();
        }
    
        @Override
        protected void configure(HttpSecurity httpSecurity) throws Exception {
            httpSecurity.formLogin(). // 设置登陆行为方式为表单登陆
                    // 登陆请求参数设置
                    usernameParameter("username").
                    passwordParameter("password").
    
                    loginPage("/login.html"). // 设置登陆页面URL路径
                    loginProcessingUrl("/login.action"). // 设置表单提交URL路径
    
                    successForwardUrl("/main.page"). // 设置认证成功跳转URL路径 POST请求
                    failureForwardUrl("/error.page");  // 设置认证失败跳转URL路径 POST请求
    
                    //  successHandler(new FarsAuthenticationSuccessHandler("https://www.acfun.cn/")). // 使用自定义的重定向登陆
                    //  failureHandler(new FarsAuthenticationFailureHandler("/error.html")).; // 跨域处理,不需要跳转了
    
            httpSecurity.authorizeRequests().
                    regexMatchers(HttpMethod.POST, "正则表达式").permitAll(). // 还可以对符合正则表达式的请求方式进行要求,这个属性使用来制定请求的方式
    
                    antMatchers("/**/*.js", "/**/*.css", "/**/images/*.*").permitAll(). // 静态资源放行
    
                    antMatchers("/login.html").permitAll(). // 登陆页面允许任意访问
                    antMatchers("/error.html").permitAll(). // 失败跳转后重定向的页面也需要被允许访问
                    antMatchers("/admin.page").hasAnyAuthority("admin").
    
                    /*antMatchers("/vip-01.page").hasAnyAuthority("vip-01").*/
                    antMatchers("/vip-01.page").hasRole("vip-01").
                    antMatchers("/ip.page").hasIpAddress("192.168.43.180").
    
                    // mvcMatchers("/main.page").servletPath("/xxx").permitAll(). // mvcMatchers资源放行匹配
                    // antMatchers("/xxx/main.page").permitAll(). // 或者多写MSP的前缀
    
                    anyRequest().authenticated(); // 其他请求均需要被授权访问
                    // anyRequest().access("@customServiceImpl.hasPermission(request, authentication)"); // 自定义Access配置
    
            // CSRF攻击拦截关闭
            httpSecurity.csrf().disable();
            httpSecurity.exceptionHandling().accessDeniedHandler(accessDeniedHandler);
    
    
            // 记住我
            httpSecurity.rememberMe().
                    tokenValiditySeconds(60). // 设置Token有效时间, 以秒为单位取值
                    userDetailsService(userDetailsService).
                    tokenRepository(persistentTokenRepository);
        }
    }

    除了使用持久化Token管理,另外一个是MemToken就是保存在内存中,应用程序来管理的

    因为Token持久化接口仅有这两个实现,或者我们也可以自己写实现:

    数据表的生成在Jdbc令牌持久化接口实现类中定义好了SQL语句,自动管理:

    侧重点还需要这三个Bean的注入

  • 相关阅读:
    mvc razor中renderPartial,RenderAction,Partial,Action的使用选择
    jquery最常用的几个方法。——可删除
    配置文件参数引用
    tinkphp5.0目录结构说明
    ionic ios上状态栏和app重叠解决方案
    cordova-plugin-alipay-v2使用篇(更新至20170725)(亲测可用)
    Ionic2 App Import BrowserAnimationsModule or NoopAnimationsModule问题
    ionic3.0 中带顶部导航的下拉刷新列表的实现
    npm install 时 提示err code EINTEGRITY报错
    ionic3.0 alipay-base插件移除后会添加多余的链接文件在nodes-modules中,导致再安装其他插件或移除插件时报错问题
  • 原文地址:https://www.cnblogs.com/mindzone/p/13747690.html
Copyright © 2011-2022 走看看