GenericFilterBean响应错误仅单端点生效问题求助
排查JWT过滤器部分端点不返回错误响应的问题
我实现了一个继承GenericFilterBean的JWT令牌过滤器,代码如下:
public class AuthFilter extends GenericFilterBean { @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { HttpServletRequest httpRequest = (HttpServletRequest) servletRequest; HttpServletResponse httpResponse = (HttpServletResponse) servletResponse; String authHeader = httpRequest.getHeader("Authorization"); if (authHeader != null){ String[] authHeaderArr = authHeader.split("Bearer"); if(authHeaderArr.length > 1 && authHeaderArr[1] != null) { String token = authHeaderArr[1]; try { Claims claims = Jwts.parserBuilder().setSigningKey(Constants.API_SECRET_KEY).build() .parseClaimsJws(token).getBody(); httpRequest.setAttribute("userId", Long.parseLong(claims.get("userId").toString())); }catch (Exception e) { httpResponse.sendError(HttpStatus.FORBIDDEN.value(), "invalid/expired token"); } } else { httpResponse.sendError(HttpStatus.FORBIDDEN.value(), "Authorization token must be Bearer[token]"); } } else { httpResponse.sendError(HttpStatus.FORBIDDEN.value(), "Authorization token must be provided"); } filterChain.doFilter(servletRequest, servletResponse); } }
问题现象
过滤器可正常匹配配置的URL规则,调试确认所有配置端点都会进入doFilter方法,但JWT令牌错误时的错误响应仅在一个端点生效:
- 正常生效:Fleet相关接口,能正确返回403错误提示
- 失效:其他端点(如用户账户接口)无错误响应返回
过滤器注册代码如下:
public class WeyApplication { public static void main(String[] args) { SpringApplication.run(WeyApplication.class, args); } @Bean public FilterRegistrationBean<AuthFilter> filterRegistrationBean () { FilterRegistrationBean<AuthFilter> registrationBean = new FilterRegistrationBean<>(); registrationBean.setFilter(new AuthFilter()); registrationBean.addUrlPatterns( "/api/en/fleet/*", "/api/en/users/*", "/api/en/ride/*", "/api/en/ride-request/*" ); return registrationBean; } }
我确认问题不在URL规则上,求排查解决。
核心问题与修复方案
问题根源
在调用httpResponse.sendError()后,你没有终止过滤器链的执行,后续的filterChain.doFilter()依然会被调用。这会导致后续的Servlet/Controller继续处理请求,可能覆盖过滤器设置的错误响应。
修复步骤
修改doFilter方法,在调用sendError()后立即return,停止过滤器链的后续执行:
public class AuthFilter extends GenericFilterBean { @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { HttpServletRequest httpRequest = (HttpServletRequest) servletRequest; HttpServletResponse httpResponse = (HttpServletResponse) servletResponse; String authHeader = httpRequest.getHeader("Authorization"); if (authHeader != null){ String[] authHeaderArr = authHeader.split("Bearer"); if(authHeaderArr.length > 1 && authHeaderArr[1] != null) { String token = authHeaderArr[1].trim(); // 新增:去除token前后空格 try { Claims claims = Jwts.parserBuilder().setSigningKey(Constants.API_SECRET_KEY).build() .parseClaimsJws(token).getBody(); httpRequest.setAttribute("userId", claims.get("userId", Long.class)); // 优化:直接获取Long类型 filterChain.doFilter(servletRequest, servletResponse); // 验证通过才继续执行过滤器链 }catch (Exception e) { httpResponse.sendError(HttpStatus.FORBIDDEN.value(), "invalid/expired token"); return; // 终止后续执行 } } else { httpResponse.sendError(HttpStatus.FORBIDDEN.value(), "Authorization token must be Bearer[token]"); return; // 终止后续执行 } } else { httpResponse.sendError(HttpStatus.FORBIDDEN.value(), "Authorization token must be provided"); return; // 终止后续执行 } } }
额外优化点
- Bearer token分割逻辑修正:原代码用
split("Bearer")会导致如果令牌包含"Bearer"字符串时分割错误,建议改为按空格分割:if (authHeader.startsWith("Bearer ")) { String token = authHeader.substring(7).trim(); // 后续验证逻辑 } else { httpResponse.sendError(HttpStatus.FORBIDDEN.value(), "Authorization token must be Bearer <token>"); return; } - userId类型安全解析:用
claims.get("userId", Long.class)替代字符串转Long,避免类型转换异常。
内容的提问来源于stack exchange,提问作者Ivan
相关产品推荐
相关产品推荐

