19

I would like to do cross origin communication using Grails in server side. The only documentation that I found is this one

https://grails.org/plugin/cors

but this is for an old version of Grails. The other documentation that I found is for spring:

https://spring.io/guides/gs/rest-service-cors/

so I added the file SimpleCorsFilter.groovy to init/myproject/ folder, but I don't know how to wire this component into resources.groovy

cfrick
  • 29,743
  • 4
  • 46
  • 59
Luis Vargas
  • 2,146
  • 1
  • 12
  • 27

7 Answers7

26

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

Ratata Tata
  • 2,545
  • 29
  • 46
  • what is the solution for Grails 2.5.0 ? i am getting `from origin 'http://localhost:8080' 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.` – Wit Wikky Apr 16 '19 at 06:39
  • This works if your backend server and client are running HTTP. If SSL is enabled, this is no longer sufficient. – beechovsky Jul 17 '20 at 23:11
12

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.

David Tinker
  • 8,541
  • 8
  • 54
  • 83
  • This didn't seem to work for me. I'm using Grails 2.5.4, and creating the `CorsFilter` class in src/groovy and then defining the bean in **resources.groovy** didn't wire up the filter. – Marty Chang Aug 06 '16 at 02:56
  • Never mind. I misunderstood the comment. Using the Grails 2.x plugin here seems to be working for me: https://github.com/davidtinker/grails-cors Thanks David! – Marty Chang Aug 06 '16 at 03:15
9

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 }
}
paulkav1
  • 419
  • 3
  • 4
6

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.

Community
  • 1
  • 1
user215556
  • 121
  • 2
  • 4
3

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.

Tegi
  • 708
  • 7
  • 14
3

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

Spiros
  • 49
  • 2
0

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)
}
Victor Soares
  • 423
  • 1
  • 4
  • 22