Spring Security6 自定义登录请求参数名称

在 Spring Security6 中,自定义登录请求参数名称(如将默认的 username 和 password 改为其他名称)需要通过配置 formLogin() 方法实现。以下是具体步骤和示例代码:

配置 SecurityFilterChain

在 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();
    }

}

关键代码说明:

usernameParameter() 方法

设置表单中用户名的参数名,默认为 username。源码如下:

/**
 * 执行身份验证时用于查找用户名的HTTP参数,默认值为 “username”。
 * @param usernameParameter 执行身份验证时用于查找用户名的HTTP参数
 * @return the {@link FormLoginConfigurer} for additional customization
 */
public FormLoginConfigurer<H> usernameParameter(String usernameParameter) {
    getAuthenticationFilter().setUsernameParameter(usernameParameter);
    return this;
}

passwordParameter() 方法

设置表单中密码的参数名,默认为 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 过滤器,下面是该过滤器成员变量的定义,如下图:

image.png

注意,上面成员变量中,postOnly=true 表示默认情况下只允许 POST 请求。

为了更进一步了解信息,我们可以在 attemptAuthentication(HttpServletRequest, HttpServletResponse) 方法上打一个断点进行观察,如下图:

image.png

继续查看“线程和变量”控制面板,展开 this 对象,发现我们设置到参数名称了吗?就是我们设置的参数“myUsername”和“myPassword”,如下图:

image.png

继续查看 attemptAuthentication() 方法中用于获取用户名和密码的方法 obtainUsername()obtainPassword(),它们使用了我们设置的参数名称从 HttpServletRequest 中获取请求参数,如下图:

image.png

最终从 HttpServletRequest 中获取的参数信息如下图:

image.png

到这里,关于请求参数的源码分析完成。后续章节将介绍 Spring Security 自定义登录成功处理

说说我的看法
全部评论(
没有评论
关于
本网站专注于 Java、数据库(MySQL、Oracle)、Linux、软件架构及大数据等多领域技术知识分享。涵盖丰富的原创与精选技术文章,助力技术传播与交流。无论是技术新手渴望入门,还是资深开发者寻求进阶,这里都能为您提供深度见解与实用经验,让复杂编码变得轻松易懂,携手共赴技术提升新高度。如有侵权,请来信告知:hxstrive@outlook.com
其他应用
公众号