如何配置springdoc-openapi使Spring Security表单登录支持form-urlencoded?
解决SpringDoc表单登录端点请求体类型配置问题
问题背景
使用SpringBoot 2.7.5 + Spring Security 5.7.4集成springdoc-openapi-ui时,通过springdoc.show-login-endpoint=true暴露的登录端点仅支持application/json请求体,导致UsernamePasswordAuthenticationFilter无法获取用户名和密码,需将请求体改为application/x-www-form-urlencoded。
解决方案
通过自定义OpenApiCustomizer修改登录端点的请求体配置,同时确保Spring Security配置正确。
1. 自定义OpenAPI配置类
创建配置类覆盖登录端点的请求体定义,将媒体类型改为表单格式:
import io.swagger.v3.oas.models.OpenAPI; import io.swagger.v3.oas.models.Operation; import io.swagger.v3.oas.models.PathItem; import io.swagger.v3.oas.models.media.Content; import io.swagger.v3.oas.models.media.MediaType; import io.swagger.v3.oas.models.media.Schema; import io.swagger.v3.oas.models.parameters.RequestBody; import org.springdoc.core.customizers.OpenApiCustomizer; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class SpringDocConfig { @Bean public OpenApiCustomizer loginEndpointCustomizer() { return openApi -> { // 定位登录端点路径(默认是"/login",自定义登录路径需同步修改) PathItem loginPath = openApi.getPaths().get("/login"); if (loginPath != null) { Operation postLoginOp = loginPath.getPost(); if (postLoginOp != null) { // 构建表单类型请求体 RequestBody formRequestBody = new RequestBody() .description("登录凭证") .content(new Content() .addMediaType("application/x-www-form-urlencoded", new MediaType().schema(new Schema<>() .type("object") .addProperty("username", new Schema<>().type("string")) .addProperty("password", new Schema<>().type("string"))))); postLoginOp.setRequestBody(formRequestBody); } } }; } }
2. 配置Spring Security
确保Swagger相关路径允许匿名访问,同时表单登录配置正确:
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.web.SecurityFilterChain; @Configuration @EnableWebSecurity public class SecurityConfig { @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http .authorizeHttpRequests(auth -> auth // 允许Swagger资源无需认证 .antMatchers("/swagger-ui/**", "/v3/api-docs/**").permitAll() // 保护目标端点 .antMatchers("/foos/**").authenticated() .anyRequest().permitAll() ) .formLogin(form -> form // 登录处理路径需与OpenAPI配置中的路径一致 .loginProcessingUrl("/login") .permitAll() ) .csrf(csrf -> csrf.disable()); // 若需CSRF保护,可根据业务调整 return http.build(); } }
原理说明
- Spring Security的
UsernamePasswordAuthenticationFilter默认从请求参数中提取username和password,而非JSON请求体,因此将Swagger登录端点的请求体改为表单格式后,凭证可被正确识别。 - 自定义的
OpenApiCustomizer会修改OpenAPI文档中登录端点的POST请求定义,替换原有JSON媒体类型为表单类型,Swagger UI将自动渲染表单输入框供用户提交凭证。
内容的提问来源于stack exchange,提问作者Adrian Bob
相关产品推荐
相关产品推荐

