在使用 Spring Security 6 框架时,如果没有配置自定义的登陆页面,Spring Security 6 默认会提供一个登陆页面,如下图:

注意:该登陆页面使用了 bootstrap 作为样式库,由于 bootstrap 库在外网,访问有时会失败。
虽然 Spring Security6 给我们提供了登录页面,但是在实际项目中,大多喜欢使用自己的登录页面。所以 Spring Security 6 中不仅仅提供了登录页面,还支持用户自定义登录页面。实现过程也比较简单,只需要修改配置类即可。完整的自定义登陆页面操作流程如下:
下面是自定义登陆页面示例项目的结构图:

上图中,我们自定义了登陆页面(login.html)、成功(success.html)和失败(fail.html)页面。
自定义登陆页面使用 thymeleaf 技术实现,因此需要引入如下依赖:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>自定义登录</title>
</head>
<body>
<h1>自定义登录页面</h1>
<form action="/login" method="post">
<p>
用户名:<input type="text" name="username" placeholder="请输入用户名" />
</p>
<p>
密码:<input type="password" name="password" placeholder="请输入密码" />
</p>
<p>
<input type="submit" value="登录"/>
</p>
</form>
</body>
</html>注意,完整依赖信息查看“Spring Security6 入门示例”。
Thymeleaf 简介
Thymeleaf 是一款现代化的服务器端 Java 模板引擎,专为 Web 和独立环境应用程序设计。它能够处理 HTML、XML、JavaScript、CSS 甚至纯文本,在前后端分离的架构中扮演着重要角色。
自定义一个登录页面,登录表单的地址为 /login(其实可以自定义该地址,后续介绍),请求方式为 post,如下:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>登录成功</title>
</head>
<body>
<h1>登录成功,欢迎光临!</h1>
</body>
</html>注意:
用户名输入框的 name 必须为 username(注意:可以自定义,后续介绍)
密码输入框的 name 必须为 password(注意:可以自定义,后续介绍)
登录成功页面结构简单,仅仅显示“登录成功,欢迎光临!”信息,如下:
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>登录成功</title> </head> <body> <h1>登录成功,欢迎光临!</h1> </body> </html>登录失败页面结构简单,仅仅显示“登录失败,用户名/密码错误”信息,如下:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>登录失败</title>
</head>
<body>
<h1 style="color:red;">登录失败,用户名/密码错误</h1>
</body>
</html>创建 ViewController 控制器,分别提供登录、成功和失败页面的视图,如下图:
package com.hxstrive.spring_security.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
/**
* 视图控制器
* @author hxstrive.com
*/
@Controller
@RequestMapping("/view")
public class ViewController {
// 成功页面
@RequestMapping("/login")
public String login() {
return "login";
}
// 成功页面
@RequestMapping("/success")
public String success() {
return "success";
}
// 失败页面
@RequestMapping("/fail")
public String fail() {
return "fail";
}
}创建 CustomUserDetailsService 类,实现 UserDetailsService 接口,为了项目演示,简单的验证用户账号是否为“admin”,密码设置为 123456,如下:
package com.hxstrive.spring_security.config;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
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.bcrypt.BCryptPasswordEncoder;
import java.util.ArrayList;
import java.util.List;
/**
* 自定义实现 UserDetailsService 接口
* @author hxstrive.com
*/
public class CustomUserDetailsService implements UserDetailsService {
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
System.out.println("loadUserByUsername(String username) :: " + username);
// 模拟从数据库中加载用户信息
if ("admin".equals(username)) {
// 创建用户权限列表
List<GrantedAuthority> authorities = new ArrayList<>();
authorities.add(new SimpleGrantedAuthority("ROLE_ADMIN"));
// 创建 UserDetails 对象
// 注意,密码通过 BCryptPasswordEncoder 进行加密获得
// 正常情况下,密码从数据库查询
String password = new BCryptPasswordEncoder().encode("123456");
return new User(username, password, authorities);
} else {
throw new UsernameNotFoundException("User not found with username: " + username);
}
}
}创建 @Configuration 配置类 SecurityConfig,使用 @Bean 分别配置 CustomUserDetailsService 和 BCryptPasswordEncoder 的实例,如下:
package com.hxstrive.spring_security.config;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
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.configurers.AbstractAuthenticationFilterConfigurer;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
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.SecurityFilterChain;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.ForwardAuthenticationFailureHandler;
import java.io.IOException;
import static org.springframework.security.config.Customizer.withDefaults;
/**
* Spring Security 配置类
* @author hxstrive.com
*/
@Configuration
public class SecurityConfig {
// 自定义登录页面,需要配置
@Bean
public UserDetailsService userDetailsService() {
System.out.println("userDetailsService()");
return new CustomUserDetailsService();
}
@Bean
public PasswordEncoder passwordEncoder() {
System.out.println("passwordEncoder()");
return new BCryptPasswordEncoder();
}
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
System.out.println("securityFilterChain()");
// csrf 设置
// csrfCustomizer.ignoringRequestMatchers(*) 表示所有请求地址都不使用 csrf
http.csrf(csrfCustomizer -> csrfCustomizer.ignoringRequestMatchers("*"))
// authorize.anyRequest().authenticated() 表示所有的请求都需要进行身份验证。
.authorizeHttpRequests(authorize -> authorize
// 配置登陆失败页面访问不需要鉴权
// 如果不配置,不会跳转到登录失败页面
// 因为跳转到登录失败,由于未授权,又重定向到登录页面
.requestMatchers("/view/login", "/view/fail").permitAll()
.anyRequest().authenticated())
// formLogin() 用于配置表单登录功能
.formLogin(e -> e.loginProcessingUrl("/login") // 配置处理登陆请求到地址
// 自定义登陆页面地址
.loginPage("/view/login")
// 自定义登陆成功页面
.defaultSuccessUrl("/view/success")
// 登陆失败页面
.failureUrl("/view/fail")
.permitAll())
// httpBasic() 启用 HTTP 基本认证,withDefaults() 表示使用默认的 HTTP 基本认证配置。
.httpBasic(withDefaults());
return http.build();
}
}配置说明:
(1)CSRF 配置
// 生产环境下不建议忽略所有请求
http.csrf(csrfCustomizer -> csrfCustomizer.ignoringRequestMatchers("*"))上述代码,crsf() 用于配置跨站请求伪造(CSRF)保护。csrfCustomizer.ignoringRequestMatchers("*") 表示忽略所有请求的 CSRF 检查。这在一些场景下可能是为了测试方便或者特定的业务需求,但在生产环境中这样配置是不安全的,通常应该明确指定哪些请求可以忽略 CSRF 检查,而不是全部忽略。
(2)请求授权配置
.authorizeHttpRequests(authorize -> authorize
.requestMatchers("/view/login", "/view/fail").permitAll()
.anyRequest().authenticated())authorizeHttpRequests() 用于配置 HTTP 请求的授权规则:
requestMatchers("/view/login", "/view/fail").permitAll() 表示对 /view/login 和 /view/fail 这两个请求路径,允许所有用户访问,无需进行身份验证。
anyRequest().authenticated() 表示除了前面指定的允许的请求外,其他任何请求都需要用户进行身份验证后才能访问。
(3)表单登录配置
.formLogin(e -> e.loginProcessingUrl("/login")
.loginPage("/view/login")
.defaultSuccessUrl("/view/success")
.failureUrl("/view/fail")
.permitAll())formLogin() 用于配置基于表单的登录相关设置:
loginProcessingUrl("/login") 配置处理登录表单提交的 URL,当用户提交登录表单时,Spring Security 会将请求发送到这个 URL 进行身份验证。
loginPage("/view/login") 配置自定义的登录页面的路径,用户访问这个路径会看到登录页面。
defaultSuccessUrl("/view/success") 配置用户成功登录后默认重定向的 URL。
如果用户访问 http://localhost:8080/hello 地址,由于没有权限,将跳转到登录页面 http://localhost:8080/view/login,登录成功将跳转到 http://localhost:8080/hello 地址(即上次访问的地址)。
如果用户直接访问登录页面 http://localhost:8080/view/login,登录成功将跳转到 http://localhost:8080/view/success 地址。
failureUrl("/view/fail") 配置用户登录失败后重定向的 URL 地址。
permitAll() 配置登录相关的请求(如访问登录页面、处理登录请求等),允许所有用户访问。
(4)HTTP Basic 配置
.httpBasic(withDefaults())httpBasic() 配置了 HTTP Basic 认证,withDefaults() 表示使用默认的 HTTP Basic 认证配置。HTTP Basic 认证是一种简单的认证方式,客户端通过在请求头中发送用户名和密码(经过 Base64 编码)来进行身份验证。
该控制器仅提供一个简单的 /hello 接口,该接口返回固定值,如下:
package com.hxstrive.spring_security.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* 简单控制器
* @author hxstrive.com
*/
@RestController
public class HelloController {
@GetMapping("/hello")
public String hello() {
return "Hello, Spring Security!";
}
}使用 @SpringBootApplication 和 @EnableWebSecurity 注解修饰入口类,如下:
package com.hxstrive.spring_security;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
/**
* 入口类
* @author hxstrive.com
*/
@SpringBootApplication
@EnableWebSecurity
public class SpringSecurityDemo4Application {
public static void main(String[] args) {
SpringApplication.run(SpringSecurityDemo4Application.class, args);
}
}在 IDE 中运行 Spring Boot 应用程序的主类(通常是带有 @SpringBootApplication 注解的类),监听 8080 端口。
打开浏览器,访问 http://localhost:8080/hello 地址,由于所有请求都需要身份验证,你会看到自定义的登录页面,如下图:

输入用户名(admin)和密码(123456),点击“登录”按钮,登录成功将会跳转到登录成功页面,如下图:

如果输入的用户名或密码错误,将会跳转到登录失败页面,如下图:

到这里,详细介绍了如何自定义登录页面,后续将介绍如何自定义登录请求参数名称。