-
Notifications
You must be signed in to change notification settings - Fork 563
DATAREST-573 Add support for Spring Web MVC CORS configuration mechanisms. #233
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
Conversation
…oduced in Spring 4.2. Prepare issue branch.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great one. Added a few minor comments. I wouldn't mind having @sdeleuze skim over the changes, especially the parts that use the new API for whether he can detect some usage patterns that look unnatural.
String repositoryLookupPath = new BaseUri(configuration.getBaseUri()).getRepositoryLookupPath(lookupPath); | ||
|
||
// Repository root resource | ||
if (StringUtils.hasText(repositoryLookupPath) && repositories != null) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we invert the conditions to be able to use early returns and thus avoid the nesting?
*/ | ||
CorsConfigurationAccessor(ResourceMappings mappings, Repositories repositories, | ||
StringValueResolver embeddedValueResolver) { | ||
this.mappings = mappings; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Non-null assertions missing.
CorsConfiguration findCorsConfiguration(String lookupPath) { | ||
|
||
ResourceMetadata resource = getResourceMetadata(getRepositoryBasePath(lookupPath)); | ||
if (resource != null) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ternary if?
} | ||
|
||
String allowCredentials = resolveCorsAnnotationValue(annotation.allowCredentials()); | ||
if ("true".equalsIgnoreCase(allowCredentials)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Insert blank line before.
* The {@link HandlerMapping} to delegate requests to Spring Data REST controllers. Sets up a | ||
* {@link DelegatingHandlerMapping} to make sure manually implemented {@link BasePathAwareController} instances that | ||
* register custom handlers for certain media types don't cause the {@link RepositoryRestHandlerMapping} to be | ||
* omitted. | ||
* |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Avoid whitespace change.
@RunWith(MockitoJUnitRunner.class) | ||
public class CorsConfigurationAccessorUnitTests { | ||
|
||
private CorsConfigurationAccessor accessor; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fields don't need to be private in tests.
} | ||
} | ||
|
||
@RepositoryRestController |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's move those classes under the test methods so that we stay consistent to other tests. Configuration can stay here.
/** | ||
* Creates a new {@link RepositoryCorsRegistry}. | ||
*/ | ||
public RepositoryCorsRegistry() {} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think we need the default constructor, do we?
* @author Mark Paluch | ||
* @since 2.6 | ||
*/ | ||
public class RepositoryCorsRegistry extends CorsRegistry { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What's the reason we need this dedicated class? It seems we could just get away with using CorsRegistry
, right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
CorsRegistry
's getCorsConfigurations
method is protected
so we need to make it usable for us. Didn't want to rely on reflection.
* | ||
* @param mappings must not be {@literal null}. | ||
* @param config must not be {@literal null}. | ||
* @param repositories must not be {@literal null}. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like repositories
can in fact be null.
|
||
== Repository interface CORS configuration | ||
|
||
You can add a `@CrossOrigin` annotation to your repository interfaces to enable CORS for the whole repository. By default `@CrossOrigin` allows origins and `HEAD` and `GET` HTTP methods: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As mentioned here, the current behaviour with Spring Data REST + @CrossOrigin
is to allow GET
and HEAD
HTTP methods (default for the low level CorsConfiguration
class).
In Spring MVC, the default behaviour for @CrossOrigin
annotations without any method specified is to use methods of the related @RequestMapping
annotation. I am wondering if by default in Spring Data REST, we could not just allow HTTP methods of the related REST endpoint, in order to avoid surprising the user when for example his repository methods exposed with a POST
HTTP method will not work by default. Any thoughts?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
GET
and HEAD
are in sync with Spring MVC (initially it's the same behavior) and to not allow any methods that change data by default.
We check the allowed methods on collection/item level inside the particular controllers – we could derive the allowed methods from there but the CORS configuration would be required to mirror the logic that is already present inside the controllers.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
After discussing with @sdeleuze, @CrossOrigin
on a repository will enable all HTTP methods by default. This default can be overridden. We can evaluate in a later step how we can provide the enabled repository methods to expose only the allowed CORS methods on a resource.
…oduced in Spring 4.2. We now support CORS configuration mechanisms introduced in Spring 4.2. CORS can be configured on multiple levels: Repository interface, Repository REST controller and global level. Spring Data REST CORS configuration is isolated so Spring Web MVC'S CORS configuration does not apply to Spring Data REST resources. Multiple configuration sources are merged so different aspects of CORS can be configured in separate locations. @crossorigin interface PersonRepository extends CrudRepository<Person, Long> {} @RepositoryRestController @RequestMapping("/person") public class PersonController { @crossorigin(maxAge = 3600) @RequestMapping(method = RequestMethod.GET, "/xml/{id}", produces = MediaType.APPLICATION_XML_VALUE) public Person retrieve(@PathVariable Long id) { // ... } } @component public class SpringDataRestCustomization extends RepositoryRestConfigurerAdapter { @OverRide public void configureRepositoryRestConfiguration(RepositoryRestConfiguration config) { config.addCorsMapping("/person/**") .allowedOrigins("http://domain2.com") .allowedMethods("PUT", "DELETE") .allowedHeaders("header1", "header2", "header3") .exposedHeaders("header1", "header2") .allowCredentials(false).maxAge(3600); } }
b223a2e
to
273dac7
Compare
Removed RepositoryRestConfiguration.addCorsMapping(…) as we currently don't have any other shortcut methods for configuration like this. Tweaked the setup of (now Repository)CorsConfigurationAccessor to be created earlier so that we avoid recreation for every lookup. Introduced a NoOpStringValueResolver to be used by default so that we don't need to deal with the case of the resolver being null at the end of the call chain. Replaced constructor of RepositoryCorsConfigurationAccessor with corresponding Lombok annotation. Updated reference documentation accordingly. Original pull request: #233.
That's been merged a while ago. |
So, which version has actually this new feature and how can I use it? |
The referenced ticket has all the information. |
We now support CORS configuration mechanisms introduced in Spring 4.2. CORS can be configured on multiple levels: Repository interface, Repository REST controller and global level. Spring Data REST CORS configuration is isolated so Spring Web MVC'S CORS configuration does not apply to Spring Data REST resources.
Multiple configuration sources are merged so different aspects of CORS can be configured in separate locations.