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?
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
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)
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With