如何在Spring Security Webflux中自定义默认未授权响应体?
解决方案
要在Spring Boot Webflux中自定义401未授权响应的JSON格式,你需要通过以下步骤实现:
1. 创建自定义错误响应DTO
首先定义一个与目标JSON结构匹配的实体类,用来生成响应内容:
import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; public class ErrorResponse { private String statusCode; private String statusMessage; private String timestamp; public ErrorResponse(String statusCode, String statusMessage) { this.statusCode = statusCode; this.statusMessage = statusMessage; // 生成符合要求的时间格式 this.timestamp = LocalDateTime.now().format(DateTimeFormatter.ofPattern("EEE MMM dd HH:mm:ss zzz yyyy")); } // Getter和Setter方法 public String getStatusCode() { return statusCode; } public void setStatusCode(String statusCode) { this.statusCode = statusCode; } public String getStatusMessage() { return statusMessage; } public void setStatusMessage(String statusMessage) { this.statusMessage = statusMessage; } public String getTimestamp() { return timestamp; } public void setTimestamp(String timestamp) { this.timestamp = timestamp; } }
2. 实现自定义认证入口点
创建ServerAuthenticationEntryPoint的实现类,负责在401时生成自定义响应:
import org.springframework.core.io.buffer.DataBuffer; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.http.server.reactive.ServerHttpResponse; import org.springframework.security.core.AuthenticationException; import org.springframework.security.web.server.ServerAuthenticationEntryPoint; import org.springframework.stereotype.Component; import reactor.core.publisher.Mono; import com.fasterxml.jackson.databind.ObjectMapper; @Component public class CustomAuthenticationEntryPoint implements ServerAuthenticationEntryPoint { private final ObjectMapper objectMapper; // 注入Spring自动配置的ObjectMapper public CustomAuthenticationEntryPoint(ObjectMapper objectMapper) { this.objectMapper = objectMapper; } @Override public Mono<Void> commence(ServerHttpResponse response, AuthenticationException ex) { // 设置响应状态码为401 response.setStatusCode(HttpStatus.UNAUTHORIZED); // 设置响应内容类型为JSON response.getHeaders().set(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE); // 构建错误响应对象 ErrorResponse errorResponse = new ErrorResponse("401", "Unauthorized"); try { // 将对象序列化为JSON字节数组 byte[] jsonBytes = objectMapper.writeValueAsBytes(errorResponse); DataBuffer buffer = response.bufferFactory().wrap(jsonBytes); // 写入响应并完成 return response.writeWith(Mono.just(buffer)); } catch (Exception e) { // 序列化失败时直接结束响应 return response.setComplete(); } } }
3. 更新Spring Security配置
在SecurityWebFilterChain中配置自定义的认证入口点,替换HTTP Basic认证的默认处理逻辑:
import org.springframework.context.annotation.Bean; import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity; import org.springframework.security.config.web.server.ServerHttpSecurity; import org.springframework.security.web.server.SecurityWebFilterChain; @EnableWebFluxSecurity public class SecurityConfig { @Bean public SecurityWebFilterChain securityFilterChain(ServerHttpSecurity http, CustomAuthenticationEntryPoint authenticationEntryPoint) { return http .cors().and() .csrf().disable() .securityContextRepository(NoOpServerSecurityContextRepository.getInstance()) .formLogin().disable() .authorizeExchange() .pathMatchers("/api/v1/get-token").hasRole("API") .anyExchange().authenticated() .and() .httpBasic() // 绑定自定义的认证入口点 .authenticationEntryPoint(authenticationEntryPoint) .and() .build(); } }
效果验证
当用户未提供有效认证信息访问受保护接口时,系统会返回如下格式的响应:
{ "statusCode": "401", "statusMessage": "Unauthorized", "timestamp": "Sun May 07 10:30:23 GMT 2023" }
内容的提问来源于stack exchange,提问作者James
相关产品推荐
相关产品推荐

