How to enable CORS in Grails 3.0.1

萝らか妹 提交于 2019-12-03 22:38:01

So, if you got here using grails 3.2.+ you can use the default way.

Go to your application.yml and add:

grails:
    cors:
        enabled: true

It will add Access-Control-Allow-Origin '*'. If you want something different, look this page

We used a normal servlet filter with an entry in resources.groovy to solve this problem:

public class CorsFilter extends OncePerRequestFilter {

    @Override
    protected void doFilterInternal(HttpServletRequest req, HttpServletResponse resp, FilterChain chain)
            throws ServletException, IOException {

        String origin = req.getHeader("Origin");

        boolean options = "OPTIONS".equals(req.getMethod());
        if (options) {
            if (origin == null) return;
            resp.addHeader("Access-Control-Allow-Headers", "origin, authorization, accept, content-type, x-requested-with");
            resp.addHeader("Access-Control-Allow-Methods", "GET, HEAD, POST, PUT, DELETE, TRACE, OPTIONS");
            resp.addHeader("Access-Control-Max-Age", "3600");
        }

        resp.addHeader("Access-Control-Allow-Origin", origin == null ? "*" : origin);
        resp.addHeader("Access-Control-Allow-Credentials", "true");

        if (!options) chain.doFilter(req, resp);
    }
}

resources.groovy:

beans = {
    corsFilter(CorsFilter)
}

This works with CORS requests using basic authentication. I wrote the Grails 2.x plugin and this seemed easier than getting it to work with Grails 3.

To be specific, here is some code that works. Notice the interceptor name must match your controller name (here, workRequest), the domain needs to be whatever you are calling from (here, localhost:8081) and it is the before() method you want:

package rest
class WorkRequestInterceptor {
boolean before() { 
    header( "Access-Control-Allow-Origin", "http://localhost:8081" )
    header( "Access-Control-Allow-Credentials", "true" )
    header( "Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE" )
    header( "Access-Control-Max-Age", "3600" )  
    true 
}

boolean after() { true }
}
user215556

I was playing around with the emberjs framework together with a Grails 3.0 rest application when I was hit by the CORS issue. Following the steps in this article http://www.greggbolinger.com/rendering-json-in-grails-for-ember-js/ helped me get further.

The article shows how you can use the new Interceptors to create a CorsInterceptor class which sets the correct headers.

class CorsInterceptor {

  CorsInterceptor() {
    matchAll()
  }

  boolean before() {
    header( "Access-Control-Allow-Origin", "http://localhost:4200" )
    header( "Access-Control-Allow-Credentials", "true" )
    header( "Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE")
    header( "Access-Control-Max-Age", "3600" )
    true
  }

  boolean after() { true }
}

This worked as expected for GET requests, but failed for POST and PUT requests. The reason for this was that an OPTIONS preflight request was sent first to http://localhost:8080/mycontroller/1234, which in my case caused a 404 not found to be returned.

With the help from this answer https://stackoverflow.com/a/31834551 I modified the CorsInterceptor class to this instead:

class CorsInterceptor {

   CorsInterceptor() {
    matchAll()
  }

  boolean before() {
    header( "Access-Control-Allow-Origin", "http://localhost:4200" )
    boolean options = ("OPTIONS" == request.method)
    if (options) {

        header( "Access-Control-Allow-Origin", "http://localhost:4200" )
        header( "Access-Control-Allow-Credentials", "true" )
        header( "Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE")
        header( "Access-Control-Max-Age", "3600" )

        response.status = 200
    }

    true 
  }

  boolean after() { true }

}

Now POST and PUT requests were working.

You should use grails 3's new Interceptor API. (https://grails.github.io/grails-doc/3.0.x/guide/single.html#interceptors)

You can create an interceptor with the grails create-interceptor command. For a CORS Interceptor I would use the after() method of this Interceptor, and set it up to match all requests (or just the requests you need). You can use the response object in this method, so setting the headers should be similar to the case described in the Spring documentation.

The cleanest and simplest solution for grails 3.1.x I found is to add the Apache default CorsFilter:

import org.apache.catalina.filters.CorsFilter

// Place your Spring DSL code here
beans = {
    corsFilter(CorsFilter) //Custom CorsFilter under src/main/java/ works as well. I prefer Apache though...
}

The answer from #user215556 works as well but the default setting of the Apache Cors filter is ok as well

If you need to enable CORS for endpoints provided by the Spring Security core/rest plugins you have to add this:

Bootstrap.groovy:

SpringSecurityUtils.clientRegisterFilter("corsFilter",
    SecurityFilterPosition.SECURITY_CONTEXT_FILTER.order - 1)

resources.groovy:

beans = {
    corsFilter(CorsFilter)
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!