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

如何在SecurityConfig类的异常处理中根据错误类型返回不同的HttpServletResponse状态码

如何在SecurityConfig类的异常处理中根据错误类型返回不同的HttpServletResponse状态码

嘿,我刚好之前做Spring Security项目时碰到过一模一样的需求,其实实现起来核心就是把你的CustomAuthenticationEntryPoint做的更“聪明”一点,让它能识别不同的异常类型,然后返回对应的状态码就行,我给你捋捋具体怎么做:

首先,你得完善那个CustomAuthenticationEntryPoint类——这个类是Spring Security用来处理未认证请求的核心入口,我们要在它的核心方法里做异常类型判断:

import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.stereotype.Component;

import java.io.IOException;

@Component
public class CustomAuthenticationEntryPoint implements AuthenticationEntryPoint {

    @Override
    public void commence(HttpServletRequest request, 
                         HttpServletResponse response, 
                         AuthenticationException authException) throws IOException {
        // 两种判断方式:优先通过异常的具体类型(更准确),也可以 fallback 到异常消息匹配
        if (authException instanceof JwtTokenInvalidException 
            || authException instanceof JwtExpiredException) {
            // 属于Token相关的错误,直接返回401未授权
            response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Token验证失败或已过期");
        } else {
            // 其他类型的认证/服务错误,返回503服务不可用
            response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE, "服务暂时无法处理请求,请稍后再试");
        }
    }
}

这里我假设你有自己定义的JWT相关异常,比如JwtTokenInvalidException(Token无效)、JwtExpiredException(Token过期),用instanceof直接判断异常类型比匹配消息字符串靠谱得多,不会因为后续消息文案调整而失效。

接下来,要把这个自定义的EntryPoint配置到你的SecurityConfig里,让Spring Security用它来接管异常处理:

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;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

@Configuration
@EnableWebSecurity
public class SecurityConfig {

    private final JwtTokenFilter jwtTokenFilter;
    private final CustomAuthenticationEntryPoint customAuthenticationEntryPoint;

    // 构造注入(如果用了Lombok的@RequiredArgsConstructor,这部分代码可以省略)
    public SecurityConfig(JwtTokenFilter jwtTokenFilter, 
                          CustomAuthenticationEntryPoint customAuthenticationEntryPoint) {
        this.jwtTokenFilter = jwtTokenFilter;
        this.customAuthenticationEntryPoint = customAuthenticationEntryPoint;
    }

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
            .csrf(csrf -> csrf.disable()) // 按需配置是否关闭CSRF
            .authorizeHttpRequests(auth -> auth
                // 配置你的公开接口,比如登录、注册这类不需要认证的接口
                .requestMatchers("/auth/**").permitAll()
                // 其余所有接口都需要认证
                .anyRequest().authenticated()
            )
            // 关键配置:指定用我们自定义的EntryPoint处理异常
            .exceptionHandling(exceptions -> exceptions
                .authenticationEntryPoint(customAuthenticationEntryPoint)
            )
            // 把JWT过滤器加到UsernamePasswordAuthenticationFilter的前面
            .addFilterBefore(jwtTokenFilter, UsernamePasswordAuthenticationFilter.class);

        return http.build();
    }
}

对了,还有个实用小细节:如果你想返回JSON格式的错误响应(而不是Spring默认的HTML页面),可以在commence方法里改一下响应头和内容,比如:

// 配置响应为JSON格式
response.setContentType("application/json;charset=UTF-8");
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
// 写出JSON响应体
response.getWriter().write("{\"code\": 401, \"message\": \"Token无效或已过期\"}");

这样前端就能直接解析JSON数据了,比默认的页面友好得多。

最后再提个注意点:确保你的JWT过滤器(JwtTokenFilter)里抛出的异常是继承自AuthenticationException的,这样才能被CustomAuthenticationEntryPoint正常捕获到哦。

内容来源于stack exchange

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.08 12:49:38