配置httpBasic()时自定义BasicAuthenticationEntryPoint未生效问题排查
问题:自定义BasicAuthenticationEntryPoint在httpBasic()配置存在时不生效
我的应用通过Basic认证(使用Authorization: Basic xxxxxxxxxx请求头)保护所有端点,为了在认证失败时返回自定义异常,我创建了自定义的EntryPoint类。但该EntryPoint仅在移除SecurityConfig中的httpBasic()配置时才会生效,否则会被忽略。相关代码如下:
@Configuration @EnableWebSecurity public class SecurityConfig { .... http .authorizeHttpRequests() .anyRequest().authenticated() .and() .httpBasic() .and() .exceptionHandling() .authenticationEntryPoint(customBasicAuthEntryPoint); return http.build(); } @Component public class CustomBasicAuthEntryPoint extends BasicAuthenticationEntryPoint { private final ObjectMapper objectMapper; public CustomBasicAuthEntryPoint(ObjectMapper objectMapper) { this.objectMapper = objectMapper; } @Override public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException { Error error = new Error(); if (authException instanceof BadCredentialsException){ error.setMessage("Unauthorized please add a basic auth"); error.setStatusCode(HttpStatus.UNAUTHORIZED.value()); error.setTimestamp(Timestamp.from(Instant.now())); } else{ error.setMessage(authException.getMessage()); error.setStatusCode(response.getStatus()); error.setTimestamp(Timestamp.from(Instant.now())); } response.setStatus(error.getStatusCode()); response.setContentType(MediaType.APPLICATION_JSON_VALUE); objectMapper.writeValue(response.getWriter(), error); } }
解决方法
当你调用httpBasic()方法时,Spring Security会自动创建并注册一个默认的BasicAuthenticationEntryPoint实例,这个实例会覆盖你在exceptionHandling()中配置的自定义EntryPoint。正确的做法是直接在httpBasic()的配置链中指定自定义EntryPoint,而非单独在exceptionHandling里配置。
修改后的SecurityConfig代码如下:
@Configuration @EnableWebSecurity public class SecurityConfig { private final CustomBasicAuthEntryPoint customBasicAuthEntryPoint; public SecurityConfig(CustomBasicAuthEntryPoint customBasicAuthEntryPoint) { this.customBasicAuthEntryPoint = customBasicAuthEntryPoint; } @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http .authorizeHttpRequests() .anyRequest().authenticated() .and() .httpBasic() .authenticationEntryPoint(customBasicAuthEntryPoint) // 在此处指定自定义EntryPoint .and() .exceptionHandling(); return http.build(); } @Component public static class CustomBasicAuthEntryPoint extends BasicAuthenticationEntryPoint { private final ObjectMapper objectMapper; public CustomBasicAuthEntryPoint(ObjectMapper objectMapper) { this.objectMapper = objectMapper; } @Override public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException { Error error = new Error(); if (authException instanceof BadCredentialsException){ error.setMessage("Unauthorized please add a basic auth"); error.setStatusCode(HttpStatus.UNAUTHORIZED.value()); error.setTimestamp(Timestamp.from(Instant.now())); } else{ error.setMessage(authException.getMessage()); error.setStatusCode(HttpStatus.UNAUTHORIZED.value()); // 显式设置401,避免response.getStatus()返回默认值 error.setTimestamp(Timestamp.from(Instant.now())); } response.setStatus(error.getStatusCode()); response.setContentType(MediaType.APPLICATION_JSON_VALUE); objectMapper.writeValue(response.getWriter(), error); } } }
额外注意两点:
- 自定义EntryPoint作为内部类时,需添加
static修饰,否则Spring无法独立实例化非静态内部类 - else分支里建议显式指定
HttpStatus.UNAUTHORIZED.value(),避免response.getStatus()返回未初始化的默认状态码
内容的提问来源于stack exchange,提问作者Lucho82
相关产品推荐
相关产品推荐

