You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

配置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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.24 04:34:59