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

Spring Boot中用Filter转发请求及解决CAS认证跳转循环问题

解决Spring Boot中跳过CAS认证的Filter无限循环问题

看起来你遇到的问题是Spring Boot和Spring MVC在Filter处理逻辑上的差异导致的——**当你对/api/路径的POST请求做forward转发时,这个转发后的内部请求会再次被你的自定义Filter拦截,从而陷入无限循环。而Spring MVC环境下可能默认限制了Filter只处理外部请求,所以没这个问题。

下面给你两个最有效的解决思路,结合代码示例来说明:


思路1:限制Filter仅处理外部请求(最推荐)

Spring Boot中,FilterRegistrationBean默认会让Filter处理所有类型的请求(包括FORWARD、INCLUDE这类内部调度请求)。你只需要指定Filter仅处理外部的REQUEST类型请求,就能避免转发后的请求再次被拦截:

@Configuration
public class WebApiConfig {
    @Bean
    public FilterRegistrationBean<SkipCasFilter> testFilterRegistration() {
        FilterRegistrationBean<SkipCasFilter> registration = new FilterRegistrationBean<>();
        registration.setFilter(new SkipCasFilter());
        registration.addUrlPatterns("/api/**");
        // 关键:只处理外部发起的请求,忽略内部forward的请求
        registration.setDispatcherTypes(DispatcherType.REQUEST);
        // 设置优先级高于CAS Filter,确保先执行
        registration.setOrder(Ordered.HIGHEST_PRECEDENCE);
        return registration;
    }

    // 你的自定义Filter
    public static class SkipCasFilter implements Filter {
        @Override
        public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
            // 直接放行给后续控制器,无需forward(forward反而会触发内部请求)
            chain.doFilter(request, response);
        }
    }
}

这里我把原来的forward改成了直接调用chain.doFilter——因为你的目标本来就是让/api/**跳过CAS认证直接到控制器,没必要做转发,直接放行更简洁。


思路2:标记请求已处理,避免重复拦截

如果因为某些原因必须保留forward逻辑,可以在请求中设置一个标记属性,Filter每次拦截时先检查这个标记,已处理过就直接放行:

public static class SkipCasFilter implements Filter {
    private static final String PROCESSED_MARK = "SKIP_CAS_PROCESSED";

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        // 检查是否已经处理过这个请求,避免循环
        if (request.getAttribute(PROCESSED_MARK) != null) {
            chain.doFilter(request, response);
            return;
        }

        HttpServletRequest httpRequest = (HttpServletRequest) request;
        String uri = httpRequest.getRequestURI();
        if (uri.startsWith("/api/")) {
            // 标记请求已处理
            request.setAttribute(PROCESSED_MARK, true);
            // 转发到目标路径
            request.getRequestDispatcher(uri).forward(request, response);
        } else {
            chain.doFilter(request, response);
        }
    }
}

额外建议:调整CAS Filter的排除规则

其实更优雅的方式是直接让CAS Filter本身跳过/api/**路径,这样你甚至不需要写自定义Filter。比如如果你用的是Spring Security集成CAS,可以在配置中添加:

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .authorizeRequests()
                .antMatchers("/api/**").permitAll() // 允许/api/**无需认证
                .anyRequest().authenticated()
            .and()
            .casAuthentication(); // 你的CAS配置
    }
}

这种方式从根源上避免了Filter拦截冲突,推荐优先考虑。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.20 12:20:28