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

如何在JwtFilter的doFilter方法中调用UserController的login方法?

在JwtFilter中调用UserController的login方法的可行方案

你在Filter里用new ModelAndView("user/login")没法触发Controller方法是正常的——ModelAndView是Spring MVC用来封装视图和数据的对象,但Filter运行在DispatcherServlet之前,根本没进入Spring MVC的处理流程,所以这个对象不会被解析执行。下面给你几个靠谱的解决方案:

方案1:使用RequestDispatcher转发请求(最推荐)

这是最符合Servlet规范的方式,直接把请求转发到你的登录接口路径,让DispatcherServlet去处理并调用对应的Controller方法:

if (authHeader == null || !authHeader.startsWith("Bearer ")) {
    // 转发到/user/login接口
    request.getRequestDispatcher("/user/login").forward(req, res);
    return; // 必须return,避免后续代码继续执行抛出异常
}

这个方案的好处是完全利用Spring MVC的原有流程,不需要额外处理参数解析、返回值渲染等问题,代码也最简洁。

方案2:注入Controller实例直接调用方法

如果你的JwtFilter是由Spring管理的(比如用@Component注解),可以直接注入UserController,然后手动调用它的login方法。不过要注意,Filter里不会自动处理@RequestBody注解,所以需要自己解析请求体:

首先改造JwtFilter:

@Component
public class JwtFilter extends GenericFilterBean {
    private final UserController userController;
    private final ObjectMapper objectMapper;

    // 构造器注入(Spring 4.3+支持)
    public JwtFilter(UserController userController, ObjectMapper objectMapper) {
        this.userController = userController;
        this.objectMapper = objectMapper;
    }

    @Override
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) res;
        String authHeader = request.getHeader("authorization");

        if ("OPTIONS".equals(request.getMethod())) {
            response.setStatus(HttpServletResponse.SC_OK);
            chain.doFilter(req, res);
        } else {
            if (authHeader == null || !authHeader.startsWith("Bearer ")) {
                // 手动解析请求体为User对象
                User loginUser = objectMapper.readValue(request.getInputStream(), User.class);
                // 调用Controller的login方法
                String loginResult = userController.login(loginUser);
                
                // 将结果写入响应
                response.setContentType("application/json;charset=UTF-8");
                response.getWriter().write(loginResult);
                response.getWriter().flush();
                return;
            } else {
                // 原有Token验证逻辑
                String token = authHeader.substring(7);
                try {
                    Claims claims = Jwts.parser().setSigningKey("secretkey").parseClaimsJws(token).getBody();
                    request.setAttribute("claims", claims);
                } catch (SignatureException e) {
                    throw new ServletException("Invalid token");
                }
                chain.doFilter(req, res);
            }
        }
    }
}

这个方案适合你需要对login方法的返回结果做自定义处理的场景,但要注意如果Controller方法有其他Spring注解(比如@Valid),你需要手动处理相关逻辑。

方案3:通过Spring的HandlerMapping调用HandlerMethod

如果需要更灵活的方式(比如不确定具体的Controller),可以利用Spring的RequestMappingHandlerMapping找到对应的处理器方法,然后通过HandlerAdapter执行它:

@Component
public class JwtFilter extends GenericFilterBean {
    private final RequestMappingHandlerMapping handlerMapping;
    private final HandlerAdapter handlerAdapter;

    public JwtFilter(RequestMappingHandlerMapping handlerMapping, HandlerAdapter handlerAdapter) {
        this.handlerMapping = handlerMapping;
        this.handlerAdapter = handlerAdapter;
    }

    @Override
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) res;
        String authHeader = request.getHeader("authorization");

        if ("OPTIONS".equals(request.getMethod())) {
            response.setStatus(HttpServletResponse.SC_OK);
            chain.doFilter(req, res);
        } else {
            if (authHeader == null || !authHeader.startsWith("Bearer ")) {
                // 包装请求,指向登录接口
                HttpServletRequest loginRequest = new HttpServletRequestWrapper(request) {
                    @Override
                    public String getRequestURI() {
                        return "/user/login";
                    }

                    @Override
                    public String getMethod() {
                        return "GET"; // 要和Controller的login方法请求方式一致
                    }
                };

                try {
                    // 找到对应的处理器链
                    HandlerExecutionChain executionChain = handlerMapping.getHandler(loginRequest);
                    if (executionChain != null) {
                        HandlerMethod handlerMethod = (HandlerMethod) executionChain.getHandler();
                        // 执行处理器方法
                        handlerAdapter.handle(loginRequest, response, handlerMethod);
                    }
                } catch (Exception e) {
                    throw new ServletException("Failed to invoke login controller", e);
                }
                return;
            } else {
                // 原有Token验证逻辑
                String token = authHeader.substring(7);
                try {
                    Claims claims = Jwts.parser().setSigningKey("secretkey").parseClaimsJws(token).getBody();
                    request.setAttribute("claims", claims);
                } catch (SignatureException e) {
                    throw new ServletException("Invalid token");
                }
                chain.doFilter(req, res);
            }
        }
    }
}

这个方案最灵活,但代码复杂度也最高,适合复杂场景下的动态调用。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 07:10:38