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

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; // 终止后续执行
        }
    }
}

额外优化点

  1. 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;
    }
    
  2. userId类型安全解析:用claims.get("userId", Long.class)替代字符串转Long,避免类型转换异常。

内容的提问来源于stack exchange,提问作者Ivan

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.25 20:42:19