创建自定义登录页面
你需要在你的前端项目中创建一个自定义的登录页面,例如login.html
,这个页面将包含一个表单用于输入用户名和密码,并提交到Spring Security的认证端点。
示例login.html
页面:
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>登录页面</title>
</head>
<body>
<form action="/login" method="post">用户名:<input type="text" name="username"><br>密码:<input type="password" name="password"><br><input name="_csrf" type="hidden" th:value="${_csrf.token}"><input type="submit" value="登录">
</form>
</body>
</html>
配置Spring Security
在SecurityConfig
类中,你需要设置自定义的登录页面。你可以使用http.formLogin()
来配置登录页面。
示例SecurityConfig
类:
@Configuration
// 配置spring的容器
public class SecurityConfig {/*** 密码加密* @return*/@Beanpublic PasswordEncoder passwordEncoder() {return new BCryptPasswordEncoder();}// 配置spring security框架的一些行为(配置我们自己的登录页,不使用默认的登录页)// 但是当配置了SecurityFilterChain这个配置类之后,springsecurity 框架的某些默认行为失效了(例如不拦截未登录的用户)// 此时应该重新配置@Bean// 安全过滤器链Beanpublic SecurityFilterChain securityFilterChain(HttpSecurity httpSecurity) throws Exception { //httpSecurity方法参数注入Beanreturn httpSecurity// 配置自己的登录页面.formLogin( (formLogin) ->{formLogin.loginProcessingUrl("/login") // 登录账户密码往哪个地址提交.loginPage("/toLogin"); // 定制登录页面}).authorizeHttpRequests((authorizeHttpRequests)->{authorizeHttpRequests.requestMatchers("/toLogin").permitAll() // 特殊情况,toLogin不需要登录就可以访问.anyRequest().authenticated(); // 除了上述特殊情况之外,其他任何请求都需要认证之后才能访问}).build();}
}
注意点:
1. 在Spring Security启用CSRF保护时,表单中需要添加一个隐藏的输入字段,用于传递CSRF令牌。
<input name="_csrf" type="hidden" th:value="${_csrf.token}">
这个字段会自动生成一个CSRF令牌,并作为表单的一部分提交。th:value="${_csrf.token}"
是 Thymeleaf 的语法,它会将CSRF令牌插入到页面中。在其他模板引擎或不使用Thymeleaf的情况下,你可以直接使用JSP或其他模板引擎的语法来输出CSRF令牌。
_csrf.token
由 Spring Security 生成,并默认存储在HttpSession
或Cookie
中。- 在 Thymeleaf 模板中,Spring Security 自动提供
${_csrf.token}
变量,
为什么需要这个CSRF令牌
CSRF令牌确保提交的表单是由合法用户发起的,而不是恶意攻击者通过伪造请求提交的。它是Spring Security的一个防护机制,默认开启。
如果你启用了Spring Security的CSRF保护,并且没有在表单中包含这个令牌,Spring Security会拒绝该请求并抛出异常。
2. loginProcessingUrl("/login")
和表单的 action="/login"
必须是相同的
为什么它们需要相同?
当收到指向 /login
的 POST 请求时,Spring Security 内部的过滤器(例如 UsernamePasswordAuthenticationFilter
)会拦截这个请求,并自动处理用户的认证逻辑。
-
action="/login"
:这是HTML表单的action
属性,指定了表单提交的目标URL。当用户在登录表单中输入用户名和密码并提交时,表单会将请求发送到/login
URL。 -
loginProcessingUrl("/login")
:这是Spring Security配置中的一部分,用来指定Spring Security应该拦截和处理哪个URL的登录请求。Spring Security默认会检查表单提交的URL,如果表单的action
和loginProcessingUrl
不一致,Spring Security将无法处理该请求。
3. loginPage("/toLogin")
loginPage("/toLogin")
不会自动解析resources/templates/
,你需要手动写@Controller
来返回login.html
。@GetMapping("/toLogin")public String toLogin(){return "login"; // 这会映射到 resources/templates/login.html}
- 默认使用 Thymeleaf 作为模板引擎(如果
spring-boot-starter-thymeleaf
依赖存在)。 - 默认查找
resources/templates/
目录。 - 拼接
.html
,最终解析路径变成resources/templates/login.html
。 - Spring Security会查找这个页面,并且默认会从
resources/templates
目录(对于使用Thymeleaf等模板引擎的情况)加载该页面。如果你使用的是普通的HTML页面,而不是模板引擎,默认则会从resources/static
目录加载页面,并且返回的时候是返回login.html。
- 默认使用 Thymeleaf 作为模板引擎(如果
.loginPage("/toLogin")
表示你定制了一个自定义的登录页面。当用户访问受保护资源但还未认证时,Spring Security 会重定向用户到这个 URL(即 /toLogin
)来展示登录表单,而不是使用 Spring Security 内置的默认登录页面。你需要在 /toLogin
地址对应的 Controller 中返回你自己的登录页面,这样用户就可以在该页面上输入用户名和密码进行登录验证。
4. 如果你单独设置了安全过滤器链 (SecurityFilterChain
),而没有设置 authorizeHttpRequests()
,那么Spring Security将不会默认进行任何请求拦截和授权控制。换句话说,Spring Security将不会对任何请求应用安全策略,除非明确进行配置。
因此我们需要配置authorizeHttpRequests这一属性
.authorizeHttpRequests((authorizeHttpRequests)->{authorizeHttpRequests.requestMatchers("/toLogin").permitAll() // 特殊情况,toLogin不需要登录就可以访问.anyRequest().authenticated(); // 除了上述特殊情况之外,其他任何请求都需要认证之后才能访问})