与 Servlet Filter 和 FilterRegistrationBean 一起使用时,跨域资源共享不起作用

Posted

技术标签:

【中文标题】与 Servlet Filter 和 FilterRegistrationBean 一起使用时,跨域资源共享不起作用【英文标题】:Cross Origin Resource Sharing not working when used with Servlet Filter and FilterRegistrationBean 【发布时间】:2018-09-19 20:18:47 【问题描述】:

总结:对于跨域请求,正在发送具有有效 JSON 的响应。 (即不发送空响应。)

我有一个如下所示的 filterRegistrationBean:

@Bean
public FilterRegistrationBean corsFilterRegistration() 
    FilterRegistrationBean filterRegistrationBean =
            new FilterRegistrationBean(corsFilter());
    filterRegistrationBean.setUrlPatterns(Collections.singleton("/getToken"));
    return filterRegistrationBean;


@Bean
public CORSFilter corsFilter() 
    return new CORSFilter();

我有一个 CORSFilter 类,如下所示:

@Component
public class CORSFilter implements Filter 
    @Autowired
    UserDao userDao;

    @Autowired
    UserController userController;


    @Override
    public void init(FilterConfig filterConfig) throws ServletException 

    

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException 
        HttpServletRequest requestToUse = (HttpServletRequest) request;
        HttpServletResponse responseToUse = (HttpServletResponse) response;
        String origin = requestToUse.getHeader("Origin");
        String username = requestToUse.getParameter("username");


        if (requestToUse.getMethod().equalsIgnoreCase("GET") && Util.falseIfAnyStringIsNull(username, origin)) 
            User user = userDao.findByUsername(username);
            if (!ObjectUtils.isEmpty(user)) 
                System.out.println("user.getDomainName()==" + user.getDomainName());
                if (origin.equalsIgnoreCase(user.getDomainName())) 
                    logger.info("Access granted");
                    responseToUse.addHeader("Access-Control-Allow-Origin", origin);
                    responseToUse.addHeader("Access-Control-Allow-Methods", "GET");
                    responseToUse.addHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
                    chain.doFilter(requestToUse, responseToUse);
                 else 
                    responseToUse.sendError(HttpServletResponse.SC_FORBIDDEN, "Invalid Origin.");
                

             else 
                responseToUse.sendError(HttpServletResponse.SC_FORBIDDEN, "Invalid Username");
            

         else 
            responseToUse.sendError(HttpServletResponse.SC_FORBIDDEN, "Invalid Credential");
        
    


    @Override
    public void destroy() 

    

如果对 /getToken 发出请求,则 CORSFilter 开始发挥作用并验证用户和来源。

这一切都很好,但问题是当我从无效的来源向 /getToken 发送获取请求时,然后在浏览器控制台中,我收到正确的消息,“No 'Access-Control-Allow-Origin'请求的资源上存在标头..." 但是如果我转到网络选项卡,那么我可以看到其中包含有效令牌的 JSON 响应。

如果我删除了上面的 CORSFilter 和 filterRegistrationBean,那么我看不到任何响应,所以我假设上面的 filter 和 registrationBean 有问题。

【问题讨论】:

【参考方案1】:

Spring 框架为此提供了 org.springframework.web.filter.CorsFilter 实现和各种功能,例如 @CrossOrigin(请参阅 the reference documentation)。

滚动您自己的过滤器实现不是一个好主意;在我的脑海中,你的实现没有处理预检请求,这可能是你现在面临的(一个)问题。

【讨论】:

我不认为我可以使用@CrossOrigin,因为可以从网络应用程序更新源。因此,我使用过滤器拦截了到 /getToken 的请求,并检查了标头中的来源是否等于数据库中的来源。这只是一个简单的获取请求,因此浏览器可能没有发送任何选项请求。即使在处理了预检请求后,我仍然会收到跨域请求的响应。

以上是关于与 Servlet Filter 和 FilterRegistrationBean 一起使用时,跨域资源共享不起作用的主要内容,如果未能解决你的问题,请参考以下文章

java---servlet与filter的联系与区别

servlet和filter的区别

Filter,Servlet,Listener区别与联系

Filter与Servlet的区别和联系

Spring filter和拦截器的区别和执行顺序

Spring filter和拦截器的区别和执行顺序