如何在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
相关产品推荐
相关产品推荐

