zoukankan      html  css  js  c++  java
  • Spring Security 实现记住我

    开篇一张图,道理全靠悟。

    示例如下:

    1.    新建Maven项目  remember_me

    2.   pom.xml

    <project xmlns="http://maven.apache.org/POM/4.0.0"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
            http://maven.apache.org/xsd/maven-4.0.0.xsd">
    
    
        <modelVersion>4.0.0</modelVersion>
        <groupId>com.java</groupId>
        <artifactId>remember_me</artifactId>
        <version>1.0.0</version>
    
        <parent>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-parent</artifactId>
            <version>2.0.5.RELEASE</version>
        </parent>
    
    
        <dependencies>
    
            <!-- Spring Boot -->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-oauth2</artifactId>
                <version>2.0.0.RELEASE</version>
            </dependency>
    
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-jdbc</artifactId>
            </dependency>
            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>druid</artifactId>
                <version>1.1.11</version>
            </dependency>
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
            </dependency>
    
    
    
            <!-- 热部署 -->
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>springloaded</artifactId>
                <version>1.2.8.RELEASE</version>
                <scope>provided</scope>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-devtools</artifactId>
                <scope>provided</scope>
            </dependency>
    
        </dependencies>
    
        <build>
            <finalName>${project.artifactId}</finalName>
            <plugins>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <configuration>
                        <source>1.8</source>
                        <target>1.8</target>
                        <encoding>UTF-8</encoding>
                    </configuration>
                </plugin>
    
                <plugin>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-maven-plugin</artifactId>
                    <executions>
                        <execution>
                            <goals>
                                <goal>repackage</goal>
                            </goals>
                        </execution>
                    </executions>
                </plugin>
            </plugins>
        </build>
    </project>

    3.   RememberMeStarter.java

    package com.java;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    
    /**
     * <blockquote><pre>
     * 
     * 主启动类
     * 
     * </pre></blockquote>
     * 
     * @author Logan
     *
     */
    @SpringBootApplication
    public class RememberMeStarter {
    
        public static void main(String[] args) {
            SpringApplication.run(RememberMeStarter.class, args);
        }
    
    }

    4.   ApplicationContextConfig.java

    package com.java.config;
    
    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;
    
    /**
     * 配置文件类
     * 
     * @author Logan
     *
     */
    @Configuration
    public class ApplicationContextConfig {
    
        /**
         * <blockquote><pre>
         * 
         * 配置密码编码器,Spring Security 5.X必须配置,否则登录时报空指针异常
         * 
         * </pre></blockquote>
         * 
         * @return
         */
        @Bean
        public PasswordEncoder passwordEncoder() {
            return new BCryptPasswordEncoder();
        }
    
    }

    5.   RepositoryConfig.java

    package com.java.config;
    
    import javax.sql.DataSource;
    
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl;
    import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;
    
    /**
     * 数据库相关配置
     * 
     * @author Logan
     *
     */
    @Configuration
    public class RepositoryConfig {
    
        @Bean
        public PersistentTokenRepository tokenRepository(DataSource dataSource) {
            JdbcTokenRepositoryImpl tokenRepository = new JdbcTokenRepositoryImpl();
            tokenRepository.setDataSource(dataSource);
            // tokenRepository.setCreateTableOnStartup(true); // 第一次启动时可使用此功能自动创建表,第二次要关闭,否则表已存在会启动报错
            return tokenRepository;
        }
    
    }

    6.   SecurityUserDetailsService.java

    package com.java.service;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.security.core.authority.AuthorityUtils;
    import org.springframework.security.core.userdetails.User;
    import org.springframework.security.core.userdetails.UserDetails;
    import org.springframework.security.core.userdetails.UserDetailsService;
    import org.springframework.security.core.userdetails.UsernameNotFoundException;
    import org.springframework.security.crypto.password.PasswordEncoder;
    import org.springframework.stereotype.Component;
    
    /**
     * UserDetailsService实现类
     * 
     * @author Logan
     *
     */
    @Component
    public class SecurityUserDetailsService implements UserDetailsService {
    
        @Autowired
        private PasswordEncoder passwordEncoder;
    
        @Override
        public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
    
            // 数据库存储密码为加密后的密文(明文为123456)
            String password = passwordEncoder.encode("123456");
    
            System.out.println("username: " + username);
            System.out.println("password: " + password);
    
            // 模拟查询数据库,获取属于Admin和Normal角色的用户
            User user = new User(username, password, AuthorityUtils.commaSeparatedStringToAuthorityList("Admin,Normal"));
    
            return user;
        }
    
    }

    7.   LoginConfig.java

    package com.java.config;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.security.config.annotation.web.builders.HttpSecurity;
    import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
    import org.springframework.security.core.userdetails.UserDetailsService;
    import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;
    
    /**
     * 登录相关配置
     * 
     * @author Logan
     *
     */
    @Configuration
    public class LoginConfig extends WebSecurityConfigurerAdapter {
    
        @Autowired
        private PersistentTokenRepository tokenRepository;
    
        @Autowired
        private UserDetailsService userDetailsService;
    
        @Override
        protected void configure(HttpSecurity http) throws Exception {
    
            http.authorizeRequests()
    
                    // 设置不需要授权的请求
                    .antMatchers("/js/*", "/login.html").permitAll()
    
                    // 其它任何请求都需要验证权限
                    .anyRequest().authenticated()
    
                    // 设置自定义表单登录页面
                    .and().formLogin().loginPage("/login.html")
    
                    // 设置登录验证请求地址为自定义登录页配置action ("/login/form")
                    .loginProcessingUrl("/login/form")
    
                    // 设置默认登录成功跳转页面
                    .defaultSuccessUrl("/main.html")
    
                    // 添加记住我功能
                    .and().rememberMe().tokenRepository(tokenRepository)
    
                    // 有效期为两周
                    .tokenValiditySeconds(3600 * 24 * 14)
    
                    // 设置UserDetailsService
                    .userDetailsService(userDetailsService)
    
                    // 暂时停用csrf,否则会影响验证
                    .and().csrf().disable();
        }
    
    }

     

    8.  src/main/resources  下文件如下

    9.   application.properties

    spring.datasource.driver-class-name=com.mysql.jdbc.Driver
    spring.datasource.url=jdbc:mysql://192.168.32.10:3306/security?useUnicode=true&characterEncoding=UTF-8
    spring.datasource.username=root
    spring.datasource.password=123456
    spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
    

    10.   login.html

    <!DOCTYPE html>
    <html>
    
        <head>
            <title>登录</title>
            <meta http-equiv="content-type" content="text/html; charset=UTF-8" />
        </head>
    
        <body>
    
            <!--登录框-->
            <div align="center">
                <h2>用户自定义登录页面</h2>
                <fieldset style=" 300px;">
                    <legend>登录框</legend>
                    <form action="/login/form" method="post">
                        <table>
                            <tr>
                                <th>用户名:</th>
                                <td><input name="username" /> </td>
                            </tr>
                            <tr>
                                <th>密码:</th>
                                <td><input type="password" name="password" /> </td>
                            </tr>
                            <tr>
                                <th>记住我:</th>
                                <td><input type="checkbox" name="remember-me" value="true" checked="checked" /></td>
                            </tr>
                            <tr>
                                <th></th>
                                <td></td>
                            </tr>
                            <tr>
                                <td colspan="2" align="center"><button type="submit">登录</button></td>
                            </tr>
                        </table>
                    </form>
                </fieldset>
    
            </div>
    
        </body>
    
    </html>

     

    11.   main.html

    <!DOCTYPE html>
    <html>
    
        <head>
            <title>首页</title>
            <meta http-equiv="content-type" content="text/html; charset=UTF-8" />
            <script type="text/javascript" src="js/jquery-3.3.1.min.js"></script>
            <script>
                function getHostMessage() {
                    $.ajax({
                        type: "get",
                        url: "/getHostMessage",
                        async: true,
                        success: function(data) {
                            $("#msg").val(JSON.stringify(data));
                        }
                    });
                }
            </script>
        </head>
    
        <body>
    
            <div>
                <h2>首页</h2>
                <table>
                    <tr>
                        <td><button onclick="getHostMessage()">获取主机信息</button></td>
                    </tr>
                </table>
    
            </div>
    
            <!--响应内容-->
            <div>
                <textarea id="msg" style=" 800px;height: 800px;"></textarea>
            </div>
    
        </body>
    
    </html>

    12.   js/jquery-3.3.1.min.js 可在官网下载

    https://code.jquery.com/jquery-3.3.1.min.js

    13.   创建数据库

    DROP DATABASE IF EXISTS security;
    CREATE DATABASE security;
    USE security;
    create table persistent_logins (
        username varchar(64) not null, 
        series varchar(64) primary key, 
        token varchar(64) not null, 
        last_used timestamp not null
    );

    14.   运行 RememberMeStarter.java , 启动测试

    浏览器输入首页  http://localhost:8080/main.html

    地址栏自动跳转到登录页面,如下:

    输入如下信息:

    User:Logan

    Password:123456

     单击【登录】按钮,自动跳转到首页。

    观察数据库,此时自动生成一条记录,username字段值为登录时使用用户名,记住我Token信息已生成。

    如下所示:

    测试【记住我】 功能是否生效

    关闭浏览器重新打开,或者关闭系统重新启动,再次访问首页,页面不再跳转到登录页,直接显示首页信息。

    如下所示:

    .

  • 相关阅读:
    discuz开发笔记
    响应式布局
    timedelta
    图片轮播
    性能
    事件捕获
    git
    css hacks
    AFNetworking 网络错误提示data转换字符串
    常见HTTP错误代码
  • 原文地址:https://www.cnblogs.com/jonban/p/rememberMe.html
Copyright © 2011-2022 走看看