New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
CORS support [SPR-9278] #13916
Comments
Keith Donald commented There is a typo above. The "full featured CORS implementation" link should be: https://bitbucket.org/jsumners/corsfilter. It would help if issues and comments were editable to correct typos (it's actually quite aggrevatong they are not). |
Marcel Overdijk commented Note that Jetty has a nice CrossOriginFilter as well: http://grepcode.com/file/repo1.maven.org/maven2/org.eclipse.jetty/jetty-servlets/7.1.4.v20100610/org/eclipse/jetty/servlets/CrossOriginFilter.java But I agree with Keith that it would be very nice if Spring MVC offers something out of the box here. |
David Bellem commented For anyone stumbling upon this now, I ended up using: Just add a filter in the web.xml and it works quite well. Moving this into Spring MVC would have made my life easier. |
Russell Allen commented I was able to add dynamic CORS pre-flight support to Spring 4 (should work with 3.1+) by overriding RequestMappingHandlerMapping's registerHandlerMethod such that it registers a dynamically created handler for the pre-flight OPTIONS request to the same url pattern on the primary request handler method. Here's the code for future reference:
The above is not the most elegant code, but it gets the job done. Obviously, anyone wishing to take this route should refactor the code and at minimum separate the handler from mapper. The above code respects header expressions properly. If the primary handler mapping declares header="!Foo", then the CORS OPTIONS handler will enforce that Foo is not in the accept headers list. Conversely, if the primary handler requires a header, then the OPTIONS handler will enforce its presence in the accept header list. Finally (IMPORTANT), the OPTIONS handler will implicitly ALLOW extraneous headers not otherwise mentioned by the primary handler. That may need to be an additional configurable behavior of the OPTIONS handler. Also, note that the In order to use this code you will need to replace the traditional RequestMappingHandlerMapping bean with the above implementation. It is defined in the Web MVC Configuration, which is easily done via java config:
Now, create the
Finally, don't forget to configure the dispatcher servlet to pass through options request in web.xml: <servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>dispatchOptionsRequest</param-name>
<param-value>true</param-value>
</init-param>
</servlet> Parting Thoughts:
Oh, one last class (used to do intercept and inject data into
|
Rossen Stoyanchev commented Thanks for sharing this approach in great detail. Adding fine-grained support on the level of a specific method is worth considering. I'm curious whether you tried using a Filter like the ones Jetty and Tomcat provide for a more centralized configuration vs adding metadata to individual |
Russell Allen commented I considered the filter approach, and it certainly has its benefits. For many, the ability to 'turn on' cross origin requests in on place across all endpoints in a server and to manager the configuration in a single location is a great solution. The down side is that it provides no fine grain control without the risk of having an ever growing set of specific configurations... configurations that are ultimately co-variant to the handler method they're managing access to. If the developer wants to constrain CORS requests on a per handler basis, then it makes sense to do that at the actual handler via an annotation. Ultimately, I suspect I may be in the minority needing/wanting that granular control. Another factor that might influence a global filter vs annotated handler debate is: What was the intent of the CORS specification? More specifically, is it ok, even expected, that a CORS pre-flight OPTIONS request can respond successfully (HTTP 2XX) and the subsequent actual request still be rejected because it's missing a required header or contains an unacceptable header? The filter approach doesn't, in my opinion, provide a precise reply to the pre-flight OPTIONS request. As a result, many clients will receive successful pre-flight responses only to have the actual request rejected. Perhaps this is ok though, since the rejection of the actual request will likely contain better information about why it failed. If the pre-flight request was rejected, the user-agent will prevent the client from seeing any response details. As you can see, there's arguments for either approach. I'm curious what others think on the matter. :) |
Rossen Stoyanchev commented Current links to Jetty's CrossOriginFilter (tests, doc) and Tomcat's CorsFilter (tests, doc). |
Rossen Stoyanchev commented The use case under under #16063 is a good one to validate against. For once the SockJsService should either build on the support provided here and/or play well with it if enabled. Also it shows that for endpoints that already have built-in CORS support, it should be easy to exclude specific URLs. |
Russell Allen commented Sébastien, if you'd like, I can post to github the annotation based CORS support that I described in the prior comment. Since that post, the code has had some testing and production exposure, and there's been a few bug fixes as a result. If that's not the approach you're taking, then no worries! :) |
Sébastien Deleuze commented Russell Allen Thanks, I am still testing various approaches, so yes I would be interested by your latest version. Did you change something about adding headers for actual requests ? |
Russell Allen commented I extracted the CORS support into a repo by itself, here: https://github.com/Russell-Allen/CrossOrigin This implementation does support custom headers on cross origin requests. The browser will pass the header key that the client is attempting to add to the primary request onto the pre-flight request's Access-Control-Request-Headers header. This implementation compares the names found in the pre-flight Access-Control-Request-Headers header to and headers conditions on the request mapping. Internally, it uses Spring's HeadersRequestCondition from the RequestMappingInfo of the primary request handler. Thus, any header that the primary request handler expects will be accepted by the pre-flight handler. Response headers are also supported. The Let me know if you have any questions. |
Pratik Parikh commented Is it possible to add test cases to Allen's Implementation and explain how this could work with Spring Data Rest. |
Eric Rath commented There's another use-case that would benefit from CORS support: static assets served via the I looked at Russell Allen's annotation-driven solution; could we also add a child element to |
Sébastien Deleuze commented I have merged today a first CORS implementation in master (see this commit), and I would be interested by your feedback. As proposed by Russell Allen, a new annotation @RestController
public class SampleController {
@CrossOrigin
@RequestMapping("/foo")
public String foo() {
// ...
}
} Various @RestController
public class SampleController {
@CrossOrigin(origin = { "http://site1.com", "http://site2.com" },
allowedHeaders = { "header1", "header2" },
exposedHeaders = { "header1", "header2" },
method = RequestMethod.DELETE,
maxAge = 123, allowCredentials = "true")
@RequestMapping(value = "/foo", method = { RequestMethod.GET, RequestMethod.POST} )
public String foo() {
// ...
}
} A Global CORS configuration is not yet implemented, and may eventually be supported through ControllerAdvice (with type level I would be interested by your feedback, so don't hesitate to give a try to our latest |
Hantsy Bai commented The fine-grained config is good, but for me, I would like use CORS config globally.
cors.enable();
|
Rossen Stoyanchev commented Hantsy Bai thanks for the comment. Note that with the current changes we are automatically "CORS aware". For example the DispatcherServlet lets preflight requests (HTTP OPTIONS) through to be handled because CORS is now a built-in feature of HandlerMapping's with In short nothing to enable. Simply start adding The addition of a CORS configuration option that's externalized (not in the controller or handler) makes sense. It would be complementary to any configuration a controller or handler might already expose. In other words a union of the two. That way you can enable commonly used headers globally as you pointed out. For the implementation a Servlet Filter is best positioned for something like this as a single component with central control. A HandlerInterceptor is not ideal. It depends on the selection of a handler and doesn't get invoked until the handler is invoked, which creates issues for preflight requests. We do have a |
Sébastien Deleuze commented I have just pushed to master global CORS configuration capabilities support, see this commit for more details. |
Hantsy Bai commented Thanks for resolving this issue. But I am a little confused about the naming. eg. CorsConfiguration For me , I perferred use "Cors" in above. Why not use "Cors" or "CrossOrigin" in these items, or there are some specific reason for this purpose? |
Sébastien Deleuze commented Since we use But this is something that we may revisit, based on feedbacks and discussion in Spring Framework team. |
Sébastien Deleuze commented I have renamed |
Fabian Wüthrich commented This new feature is great and I want to implement this in my Spring Boot / AngularJS application. All request works fine but I can't logout my user because the OPTIONS-Request to /logout is handled by Spring Security. Should I open an issue in Spring Security project or is it possible to attach CORS-Headers in LogoutSuccessHandler? |
Sébastien Deleuze commented Fabian Wüthrich Could you please create a StackOverflow question for that and add a comment here with the link? I will answer you on SO. |
Fabian Wüthrich commented Thank for the fast reply. The question ist here http://stackoverflow.com/questions/34154711/spring-security-logout-doesnt-work-with-spring-4-cors |
Keith Donald opened SPR-9278 and commented
Cross origin resource sharing (CORS) is a relevant spec these days with the emergence of HTML5 & JS clients that consume data via REST APIs. For a given app, in many cases the host that serves the JS (e.g. foo.com) is different than the host that serves the data (e.g. api.foo.com). In this case, CORS can enable the cross-domain communication.
It would be useful if Spring MVC provided code & guidance on how to configure CORS when implementing a Java-backed REST API consumed by JS clients located in other domains. Prior work exists that would be a candidate for integration.
See the resources below:
CORS Spec: http://www.w3.org/TR/cors/
Basic example of a CorsFilter implementation: https://gist.github.com/2232095
What appears to be a full-featured CorsFilter implementation: https://bitbucket.org/jsumners/corsfilter
Affects: 3.1.1
Sub-tasks:
@CrossOrigin
Issue Links:
26 votes, 34 watchers
The text was updated successfully, but these errors were encountered: