Spring Security 简明教程
Spring Security - Remember Me
记住我 (Remember Me) 是 Spring Security 的一项重要功能,因此即使会话过期,用户仍可以保持登录状态。我们将在以下部分演示 Spring Security 提供的记住我功能的使用。
记住我功能执行以下重要功能。
-
首先,它会向我们使用 formLogin() 生成的默认登录表单中添加一个“记住我”(Remember Me) 复选框。
-
对于自定义登录表单,我们需要向表单中添加一个名为“remember-me”的复选框。如果需要使用不同的名称,我们需要在 Spring Security 配置期间配置新名称,如下所示:.rememberMe().rememberMeParameter("remember")
-
其次,勾选该复选框将生成记住我 cookie。Cookie 存储用户的身份,并且浏览器会对其进行存储。
-
Spring Security 在将来的会话中检测 Cookie,以便自动化登录。因此,用户无需再次登录即可再次访问该应用程序。
记住我功能可以按如下所示进行明确配置 −
protected void configure(HttpSecurity http) throws Exception {
http
// ...
// key should be unique
.rememberMe(config -> config.key("123456")
.tokenValiditySeconds(3600))
.build();
}
Important Methods
以下是我们在 logout() 方法中可以配置的重要方法。
-
*rememberMe () * − 这将用于实现记住我功能。传递给记住我功能的密钥应该是唯一而保密的。此密钥特定于应用程序,用于生成记住我令牌内容。
-
*tokenValiditySeconds () * − 这将用于设置记住我 cookie 的到期时间。默认有效期为 2 周。我们可以随时对其进行自定义,就像在上面的代码片段中一样,我们使用 3600 秒将其设置为 1 小时。
-
rememberMeParameter () * − This is used to mark an input check box to be remember-me checkbox. By default, its value is *remember-me 。
让我们使用 Spring Security 开始实际编程。在开始使用 Spring 框架编写示例之前,您必须确保已正确设置 Spring 环境,如 Spring Security - Environment Setup 章节所述。我们还假设您具备 Spring Tool Suite IDE 方面的部分工作知识。
现在,让我们开始编写一个由 Maven 管理的基于 Spring MVC 的应用程序,该应用程序将要求用户登录、认证用户,然后提供使用 Spring Security 表单登录功能注销的选项。
Create Project using Spring Initializr
Spring Initializr 是开始 Spring Boot 项目的一个好方法。它提供了一个易于使用的用户界面来创建项目、添加依赖项、选择 Java 运行时等。它会生成一个框架项目结构,下载后可以在 Spring Tool Suite 中导入,然后我们可以使用现成的项目结构继续进行。
我们选择了一个 maven 项目,将项目命名为 formlogin,并将 java 版本指定为 21。添加了以下依赖项:
-
Spring Web
-
Spring Security
-
Spring Boot DevTools
Thymeleaf 是 Java 的模板引擎。它使我们能够快速开发用于在浏览器中渲染的静态或动态网页。它已得到极大的扩展,它允许我们定义和定制精细处理的模板。除此之外,我们可以通过点击 link 来了解更多有关 Thymeleaf 的信息。
让我们开始生成并下载项目。然后我们将它解压到我们选择的文件夹中并使用任何 IDE 来打开它。我将使用 Spring Tools Suite 4 。它可以从 https://spring.io/tools 网站免费下载,且已针对 spring 应用进行优化。
pom.xml with all relevant dependencies
让我们看一看我们的 pom.xml 文件。它应该与以下内容类似 −
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.3.1</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.tutorialspoint.security</groupId>
<artifactId>formlogin</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>formlogin</name>
<description>Demo project for Spring Boot</description>
<url/>
<licenses>
<license/>
</licenses>
<developers>
<developer/>
</developers>
<scm>
<connection/>
<developerConnection/>
<tag/>
<url/>
</scm>
<properties>
<java.version>21</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.thymeleaf.extras</groupId>
<artifactId>thymeleaf-extras-springsecurity6</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
Spring Security Configuration Class
在我们的 config 包中,我们创建了 WebSecurityConfig 类。我们将使用此类来进行我们的安全配置,因此让我们用 @Configuration 注解和 @EnableWebSecurity 为它添加注释。因此,Spring Security 知道将此类视为配置类。正如我们所看到的,Spring 让我们能很轻松地配置应用。
WebSecurityConfig
package com.tutorialspoint.security.formlogin.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
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.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.web.SecurityFilterChain;
@Configuration
@EnableWebSecurity
public class WebSecurityConfig {
@Bean
protected UserDetailsService userDetailsService() {
UserDetails user = User.builder()
.username("user")
.password(passwordEncoder().encode("user123"))
.roles("USER")
.build();
UserDetails admin = User.builder()
.username("admin")
.password(passwordEncoder().encode("admin123"))
.roles("USER", "ADMIN")
.build();
return new InMemoryUserDetailsManager(user, admin);
}
@Bean
protected PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
protected SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
return http
.csrf(AbstractHttpConfigurer::disable)
.authorizeHttpRequests(
request -> request.requestMatchers("/login").permitAll()
.requestMatchers("/**").authenticated()
)
.formLogin(form -> form.loginPage("/login")
.defaultSuccessUrl("/")
.failureUrl("/login?error=true")
.permitAll())
.rememberMe(config -> config.key("123456")
.tokenValiditySeconds(3600))
.logout(config -> config
.logoutUrl("/logout")
.logoutSuccessUrl("/login")
.invalidateHttpSession(true)
.deleteCookies("JSESSIONID"))
.build();
}
}
我们在此处提到了具有弹性安全密匙的 rememberMe()。
Controller Class
在此类中,我们为该应用程序的索引页和登录页创建了 "/" 端点和 "/login" 的映射。
AuthController.java
package com.tutorialspoint.security.formlogin.controllers;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
@Controller
public class AuthController {
@GetMapping("/")
public String home() {
return "index";
}
@GetMapping("/login")
public String login() {
return "login";
}
}
Views
让我们在 /src/main/resources/templates 文件夹中创建 index.html,并添加以下内容以用作主页并显示已登录的用户名。
index.html
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:th="https://www.thymeleaf.org"
xmlns:sec="https://www.thymeleaf.org/thymeleaf-extras-springsecurity3">
<head>
<title>
Hello World!
</title>
</head>
<body>
<h1 th:inline="text">Hello <span sec:authentication="name"></span>!</h1>
<form th:action="@{/logout}" method="post">
<input type="submit" value="Sign Out"/>
</form>
</body>
<html>
login.html
让我们在 /src/main/resources/templates 文件夹中创建 login.html,并使其内容如下,以用作登录页面。我们对文本字段使用默认名称 username 、 password 和 remember-me 。对于其他名称,我们需要在 Spring 安全性配置类中设置相同的名称。
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:th="https://www.thymeleaf.org"
xmlns:sec="https://www.thymeleaf.org/thymeleaf-extras-springsecurity3">
<head>
<title>Spring Security Example</title>
</head>
<body>
<div th:if="${param.error}">
<p>Bad Credentials</p>
</div>
<div th:if="${param.logout}">You have been logged out.</div>
<form th:action="@{/login}" method="post">
<h1>Please sign in</h1>
<table>
<tr>
<td><label for="username"><b>Username</b></label></td>
<td><input type="text" placeholder="Enter Username" name="username" id="username" required></td>
</tr>
<tr>
<td><label for="password"><b>Password</b></label></td>
<td><input type="password" placeholder="Enter Password" name="password" id="password" required></td>
</tr>
<tr>
<td><label for="remember-me"><b>Remember Me</b></label> </td>
<td><input type="checkbox" name="remember-me" /></td>
</tr>
<tr>
<td> </td>
<td><input type="submit" value="Sign In" /></td>
</tr>
</table>
</form>
</body>
</html>
在登录表单中,我们使用 POST 方法登录,同时使用名称和 ID 为 username 、 password 和 remember-me 的输入字段和复选框。如果选中复选框,则当用户登录该应用程序时,将创建一个记住我 Cookie。
Running the Application
因为我们所有的组件都已就绪,让我们来运行此 Application。右击项目,选择 Run As ,然后选择 Spring Boot App 。
它将启动该应用,并且一旦应用启动,我们就可以运行 localhost:8080 来查看更改。