简体   繁体   English

如何在本地主机上的 Spring 和 Angular 2 之间启用 CORS

[英]How to enable CORS between Spring and Angular 2 on localhost

I have an old project with Java backend on Spring version 4.3.4.RELEASE and Spring security version 4.2.2.RELEASE.我在 Spring 版本 4.3.4.RELEASE 和 Spring 安全版本 4.2.2.RELEASE 上有一个带有 Java 后端的旧项目。 There is no way to update the libraries, I have to work with what there is.没有办法更新库,我必须使用现有的库。 The project is not REST API, does not have RestController nor WebMvcConfigurer.该项目不是 REST API,没有 RestController 和 WebMvcConfigurer。 So, I configured cors as was suggested here :所以,我按照这里的建议配置了 cors :

@EnableWebSecurity
@Configuration
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

    protected SecurityConfiguration() {
        super();
    }

    @Override
    protected void configure(HttpSecurity httpSecurity) throws Exception {
        httpSecurity
                // we don't need CSRF because our token is invulnerable
                .csrf().disable()

                // don't create session
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()

                .authorizeRequests()

                // allow anonymous resource requests
                .antMatchers(HttpMethod.GET,
                        "/",
                        "/*.html",
                        "/favicon.ico",
                        "/**/*.html",
                        "/**/*.css",
                        "/**/*.js")
                .permitAll()
                .antMatchers(HttpMethod.POST, "/rpc/*").permitAll()
                .anyRequest().permitAll();

        httpSecurity.addFilterBefore(new CorsFilter(), ChannelProcessingFilter.class);

        // disable page caching
        httpSecurity.headers().cacheControl();
    }
}

The Cors filter: Cors 过滤器:

@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
public class CorsFilter extends OncePerRequestFilter {

    private static final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(CorsFilter.class);

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        logger.error("CORS filter: " + request.getMethod());
        response.setHeader("Access-Control-Allow-Origin", "*");
        response.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
        response.setHeader("Access-Control-Max-Age", "3600");
        response.setHeader("Access-Control-Allow-Headers", "Content-Type, Access-Control-Allow-Headers, Authorization, X-Requested-With, xsrf-token");
        response.addHeader("Access-Control-Expose-Headers", "xsrf-token");
        if ("OPTIONS".equals(request.getMethod())) {
            response.setStatus(HttpServletResponse.SC_OK);
        } else {
            filterChain.doFilter(request, response);
        }
    }
}

In web.xml after all context-param and before listerenrs (that is the only filter in the app):在 web.xml 中所有 context-param 之后和 listeners 之前(这是应用程序中唯一的过滤器):

   <filter>
        <filter-name>springSecurityFilterChain</filter-name>
        <filter-class>web.servlet.response.CorsFilter
        </filter-class>
    </filter>

    <filter-mapping>
        <filter-name>springSecurityFilterChain</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

I run the back end on localhost:8080 and front end on localhost:8081 However, when I try to send a POST request with application/json inside, there is an error in the browser console我在 localhost:8080 上运行后端,在 localhost:8081 上运行前端但是,当我尝试发送带有 application/json 的 POST 请求时,浏览器控制台中出现错误

Access to XMLHttpRequest at 'http://localhost:8080/rpc' from origin 'http://localhost:8081' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.

Also, I would expect to see log "CORS filter: POST" on the back end, which I put there to check if it would make it to the filter, but there is no such log.另外,我希望在后端看到日志“CORS filter: POST”,我把它放在那里检查它是否会进入过滤器,但没有这样的日志。

Please, any suggestions on why is it not working?请,关于为什么它不起作用的任何建议? I need to stick to application/json in requests, and there is also an Authorization header sometimes in the app, so can't avoid cors completely.我需要在请求中坚持使用 application/json,并且有时在应用程序中还有一个 Authorization 标头,因此无法完全避免 cors。 Can this be an Angular 2 issue?这可能是 Angular 2 的问题吗?

I'm not familiar with spring or java, but I think I understand the problem.我不熟悉 spring 或 java,但我想我明白这个问题。

I assume that your logging filter does not work because spring framework short circuit that request before your filter is being executed.我假设您的日志过滤器不起作用,因为 spring 框架在您的过滤器被执行之前短路了该请求。

The issue here is probably somewhere in config, but I believe that the approach to the given problem is not right in general.这里的问题可能出在配置中的某个地方,但我认为解决给定问题的方法通常是不正确的。

CORS is created for some purposes, and by allowing requests from browser from all other origins you actually creating some potential security issues. CORS 是出于某些目的而创建的,通过允许来自所有其他来源的浏览器的请求,您实际上会产生一些潜在的安全问题。

Ideally, if both: server and client are your apps, from the client side you should make requests only to the same origin which the client app is hosted on.理想情况下,如果:服务器和客户端都是您的应用程序,则从客户端,您应该仅向托管客户端应用程序的同一来源发出请求。 So in your case locally it should make requests to localhost:8081 , you can do that by omitting host base address on client side when making requests.因此,在您本地的情况下,它应该向localhost:8081发出请求,您可以通过在发出请求时省略客户端的主机基地址来做到这一点。

To have it working, for development environment the best option is to set up proxy for angular (to proxy requests from localhost:8081 to localhost:8080 ), detailed setup info is here .为了让它工作,对于开发环境,最好的选择是为 angular 设置代理(代理从localhost:8081localhost:8080请求),详细的设置信息在这里

For production environment you need to host backend-server/client apps on the same origin.对于生产环境,您需要在同一来源上托管后端服务器/客户端应用程序。 You can do that by having some proxy server in front of your backend-server/client web servers, or by hosting client app (angular static output files) directly on your backend-server.您可以通过在后端服务器/客户端 Web 服务器前面设置一些代理服务器,或直接在后端服务器上托管客户端应用程序(角度静态输出文件)来实现。

Another option, is to do what you have tried to do, but do not allow requests from all origins (not .permitAll() ), instead - list specific allowed origins (like localhost:8081 ).另一种选择是做您尝试做的事情,但不允许来自所有来源的请求(不是.permitAll() ),而是 - 列出特定的允许来源(如localhost:8081 )。 But it's not that clean and also you will need to have different origins specified for development environment and for production.但这并不是那么干净,而且您还需要为开发环境和生产指定不同的来源。

This error is a result of denying OPTION web method, so you should add the following statement in the configure method:这个错误是拒绝OPTION web方法导致的,所以应该在configure方法中添加如下语句:

.antMatchers(HttpMethod.OPTIONS, "/**").permitAll()

like so:像这样:

httpSecurity
            // we don't need CSRF because our token is invulnerable
            .csrf().disable()

            // don't create session
            .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()

            .authorizeRequests()

            // allow anonymous resource requests
            .antMatchers(HttpMethod.GET,
                    "/",
                    "/*.html",
                    "/favicon.ico",
                    "/**/*.html",
                    "/**/*.css",
                    "/**/*.js")
            .permitAll()
            .antMatchers(HttpMethod.OPTIONS, "/**").permitAll()
            .antMatchers(HttpMethod.POST, "/rpc/*").permitAll()
            .anyRequest().permitAll();

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM