Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Configuring CORS with Grails 3 and Spring Security REST

I'm trying to figure out how to plug an Angular 2 frontend (running on localhost:4200) into a Grails 3 backend (running on localhost:8080) so I need to enable CORS support in the grails app.

I found this Github project (https://github.com/appcela/grails3-cors-interceptor-spring-security-rest-sample-app) that shows how to enable CORS using the grails3-cors-interceptor plugin. I'm running this very application as a test backend and I'm putting a breakpoint in CorsService.processPreflight() to check when it's called. And when I do a GET on /api/books, the browser sends an OPTIONS call first that goes through the breakpoint, but the following GET doesn't seem to go there and I can't figure out why. Any idea?

like image 577
Sebastien Avatar asked Oct 07 '16 08:10

Sebastien


2 Answers

With the latest version of Grails 3 you just need to enable CORS if your running your applications locally grails run-app. My version is Grails Version: 3.3.10. Groovy grails.cors.enabled=true

like image 133
Chaz B. Avatar answered Oct 24 '22 03:10

Chaz B.


Update

Grails 3.2.1 has inbuilt feature to support CORS. Check this out http://docs.grails.org/latest/guide/theWebLayer.html#cors

Just add this in your application.yml to enable it

grails:
    cors:
        enabled: true

(Make sure you look for the environment for which you want to enable CORS)

Original Post

You don't need a plugin (unless you want to use that plugin) to enable CORS here. Well, for your rest endpoints, you can always enable the CORS using the Grails interceptors like below:

class CorsInterceptor {

    CorsInterceptor() {
        matchAll()
    }

    boolean before() {
        if (request.method == "OPTIONS") {
            response.setHeader("Access-Control-Allow-Origin", "http://localhost:4200")
            response.setHeader("Access-Control-Allow-Credentials", "true")
            response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE")
            response.setHeader("Access-Control-Max-Age", "3600")

            response.status = 200
        }

        return true
    }

    boolean after() { true }
}

But Grails interceptors cannot intercept the endpoints provided by the Spring Security core/rest plugins since the priority of their interceptors are higher than that of Grails interceptors. So you first need to add a customer filter and then register it before the Spring related filters.

Add a file in src/main/groovy:

package test

import org.springframework.web.filter.OncePerRequestFilter

import javax.servlet.FilterChain
import javax.servlet.ServletException
import javax.servlet.http.HttpServletRequest
import javax.servlet.http.HttpServletResponse

class CorsFilter extends OncePerRequestFilter {

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

        if (req.getMethod() == "OPTIONS") {
            resp.addHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS")
            resp.addHeader("Access-Control-Max-Age", "3600")
            resp.addHeader("Access-Control-Allow-Origin", "http://localhost:4200")
            resp.addHeader("Access-Control-Allow-Credentials", "true")
            resp.status = 200
        } else {
            chain.doFilter(req, resp)
        }
    }
}

Register it on the resources.groovy:

beans = {
    corsFilterFoo(CorsFilter)
}

Now, add it to the Spring's filter chain before the security context filter (in Bootstrap.groovy):

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

References: https://github.com/grails-plugins/grails-spring-security-core/blob/v3.1.1/src/main/groovy/grails/plugin/springsecurity/SpringSecurityUtils.groovy#L698

like image 21
Shashank Agrawal Avatar answered Oct 24 '22 03:10

Shashank Agrawal