1. 程式人生 > >Spring Security 實現記住我

Spring Security 實現記住我

16px env resources 1.2 ride oauth 權限 inpu auto

開篇一張圖,道理全靠悟。

技術分享圖片

示例如下:

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. 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 ("/authentication/form")
                .loginProcessingUrl("/authentication/form")

                // 添加記住我功能
                .and().rememberMe().tokenRepository(tokenRepository)

                // 有效期為兩周
                .tokenValiditySeconds(3600 * 24 * 14)

                // 設置UserDetailsService
                .userDetailsService(userDetailsService)

                // 暫時停用csrf,否則會影響驗證
                .and().csrf().disable();
    }

}

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

技術分享圖片

8. 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
spring.datasource.dbcp2.initial-size=5
spring.datasource.dbcp2.max-total=20

9. 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="width: 300px;">
                <legend>登錄框</legend>
                <form action="/authentication/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>

10. 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="width: 800px;height: 800px;"></textarea>
        </div>

    </body>

</html>

11. js/jquery-3.3.1.min.js 可在官網下載

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

12. 創建數據庫

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
);

13. 運行 RememberMeStarter.java , 啟動測試

瀏覽器輸入首頁 http://localhost:8080/main.html

地址欄自動跳轉到登錄頁面,如下:

技術分享圖片

輸入如下信息:

User:Logan

Password:123456

單擊【登錄】按鈕,自動跳轉到首頁。

觀察數據庫,此時自動生成一條記錄,username字段值為登錄時使用用戶名,記住我Token信息已生成。

如下所示:

技術分享圖片

測試【記住我】 功能是否生效

關閉瀏覽器重新打開,或者關閉系統重新啟動,再次訪問首頁,頁面不再跳轉到登錄頁,直接顯示首頁信息。

如下所示:

技術分享圖片

.

Spring Security 實現記住我