在 Spring Security6 中,自定义登录请求参数名称(如将默认的 username 和 password 改为其他名称)需要通过配置 formLogin() 方法实现。以下是具体步骤和示例代码:
在 Security 配置类中,使用 usernameParameter() 和 passwordParameter() 方法指定自定义参数名:
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/fail").permitAll() .anyRequest().authenticated()) // formLogin() 用于配置表单登录功能 .formLogin(e -> e.loginProcessingUrl("/login") // 配置处理登陆请求到地址 // 自定义登陆页面地址 .loginPage("/view/login") // 自定义登陆参数【看这里】 .usernameParameter("myUsername") // 自定义用户名参数名称 .passwordParameter("myPassword") // 自定义密码参数名称 // 自定义登陆成功页面 .defaultSuccessUrl("/view/success") // 登陆失败页面 .failureUrl("/view/fail") .permitAll()) // httpBasic() 启用 HTTP 基本认证,withDefaults() 表示使用默认的 HTTP 基本认证配置。 .httpBasic(withDefaults()); return http.build(); } }
关键代码说明:
设置表单中用户名的参数名,默认为 username。源码如下:
/** * 执行身份验证时用于查找用户名的HTTP参数,默认值为 “username”。 * @param usernameParameter 执行身份验证时用于查找用户名的HTTP参数 * @return the {@link FormLoginConfigurer} for additional customization */ public FormLoginConfigurer<H> usernameParameter(String usernameParameter) { getAuthenticationFilter().setUsernameParameter(usernameParameter); return this; }
设置表单中密码的参数名,默认为 password。源码如下:
/** * 执行身份验证时用于查找密码的HTTP参数,默认值为 “password”。 * @param passwordParameter 执行身份验证时用于查找密码的HTTP参数 * @return the {@link FormLoginConfigurer} for additional customization */ public FormLoginConfigurer<H> passwordParameter(String passwordParameter) { getAuthenticationFilter().setPasswordParameter(passwordParameter); return this; }
修改登陆页面,确保 HTML 表单中的参数名与后续配置一致,如下:
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>自定义登录</title> </head> <body> <h1>自定义登录页面</h1> <form action="/login" method="post"> <p> <!-- 默认 name="username" --> 用户名:<input type="text" name="myUsername" placeholder="请输入用户名" /> </p> <p> <!-- 默认 name="password" --> 密码:<input type="password" name="myPassword" placeholder="请输入密码" /> </p> <p> <input type="submit" value="登录"/> </p> </form> </body> </html>
配置完成后,重启项目即可。
📢 注意事项:
(1)参数名一致性:确保 HTML 表单中的 name 属性与 usernameParameter() 和 passwordParameter() 配置一致。
(2)CSRF 保护:如果启用了 CSRF 保护(默认启用),表单需包含 CSRF 令牌(可通过 Thymeleaf 自动注入,也可以关闭 CSRF 保护)。
(3)参数类型:参数类型必须为 String,Spring Security 会自动处理编码问题。
Spring Security 中,当进行登录时会执行 UsernamePasswordAuthenticationFilter 过滤器,下面是该过滤器成员变量的定义,如下图:
注意,上面成员变量中,postOnly=true 表示默认情况下只允许 POST 请求。
为了更进一步了解信息,我们可以在 attemptAuthentication(HttpServletRequest, HttpServletResponse) 方法上打一个断点进行观察,如下图:
继续查看“线程和变量”控制面板,展开 this 对象,发现我们设置到参数名称了吗?就是我们设置的参数“myUsername”和“myPassword”,如下图:
继续查看 attemptAuthentication() 方法中用于获取用户名和密码的方法 obtainUsername() 和 obtainPassword(),它们使用了我们设置的参数名称从 HttpServletRequest 中获取请求参数,如下图:
最终从 HttpServletRequest 中获取的参数信息如下图:
到这里,关于请求参数的源码分析完成。后续章节将介绍 Spring Security 自定义登录成功处理