Wrong CORS configuration in a SpringBoot project - spring-boot

I'm developing a CRUD app that will serve REST in the SpringBoot part (it will have an Angular part too, consuming JSON). The SpringBoot part serves gracefully JSON (queries against a MySQL database) but when I run the part that tries to delete a record I get a 405 error:
"There was an unexpected error (type=Method Not Allowed, status=405)."
This is the code that fails (it's calling a #Service)
#RequestMapping(value = "/avisos/delete/{id}", method = RequestMethod.DELETE)
public ResponseEntity<Void> borraAviso(#RequestParam("id") Long id) {
boolean isRemoved;
isRemoved = avisoService.borraAviso(id);
if (!isRemoved) {
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
}
else
return new ResponseEntity<>(HttpStatus.OK);
}
This is the CORS configuration file:
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
#Configuration
public class CorsConfiguration implements WebMvcConfigurer
{
#Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("http://localhost:4200")
//.allowedMethods("GET", "POST");
.allowedMethods("");
}
}
The program runs in a Linux Mint box but I have tested that in a W8 box too and I get the same error.
(I'm using Spring Tool Suite 4, Version: 4.8.0.RELEASE, and Maven).

The declaration of the method has one issue
#RequestMapping(value = "/avisos/delete/{id}", method =
RequestMethod.DELETE) public ResponseEntity
borraAviso(#RequestParam("id") Long id) {
Here the id is a PathVariable. So the correct declaration would be
#RequestMapping(value = "/avisos/delete/{id}", method = RequestMethod.DELETE)
public ResponseEntity<Void> borraAviso(#PathVariable("id") Long id) {
By default, GET, HEAD, POST method are allowed for CORS if not overridden.
If you want to allow DELETE method, then the following config should work.
registry.addMapping("/**")
.allowedOrigins("http://localhost:4200")
.allowedMethods(HttpMethod.GET.name(),
HttpMethod.HEAD.name(),
HttpMethod.POST.name(),
HttpMethod.DELETE.name()
);

Related

Spring Boot - Cross-Origin Request Blocked (Reason: CORS header ‘Access-Control-Allow-Origin’ missing)

I have this mapping:
User 1----------------------------* Expertises
I'm using the controller SpringBoot, My contoller is
#RestController
#CrossOrigin(origins = "http://localhost:4200", "http://localhost:6227")
#RequestMapping("/api/auth")
public class UserController
{
#PostMapping("/signup/{expertises}")
public ResponseEntity<String> registerUser(#Valid #RequestBody SignUpForm signUpRequest, #PathVariable List<String> expertises)
{
}
}
I add the annotation #CrossOrigin to all the repositories
#CrossOrigin(origins = {"http://localhost:4200", "http://localhost:6227"}, methods = { RequestMethod.GET, RequestMethod.POST, RequestMethod.DELETE }, maxAge = 3600)
#Repository
public interface UserRepository extends JpaRepository<User, Long> {}
The main class is:
#SpringBootApplication
public class SpringBootJwtAuthenticationApplication {
public static void main(String[] args) {
SpringApplication.run(SpringBootJwtAuthenticationApplication.class, args);
}
#Bean
public WebMvcConfigurer configurer()
{
return new WebMvcConfigurer()
{
#Override
public void addCorsMappings(CorsRegistry registry)
{
registry.addMapping("/*")
.allowedOrigins("http://localhost:4200", "http://localhost:6227");
}
};
}
}
I added the file MyConfiguration (as Sir Ananthapadmanabhan proposed)
Front-End (Angular6)
So I want to add a list of expertises to one user using this method:
onSubmit()
{
this.submitted = true;
console.log('---------SelectedExpertise:' + this.selectedExpertiseCheckBox);
this.userService.signUpUser(this.user,
this.selectedExpertiseCheckBox)
.subscribe(data => console.log("---------------Create user:" + data)
,error => console.log(error));
this.user = new User();
}
where
signUpUser(value: any, listExp: String[]): Observable<Object>
{
return this.http.post(`${this.baseUrl}/signup/${listExp}`, value);
}
I can't do that cause adding the list of expertises. That produces this error
Have you please any idea about solving that ?.
Thanks.
As indicated on the console; it was a problem with CORS.
But in reality, it wasn't.
In fact, this bug is caused by a bad use of localStorage with front-end:
the list of strings have to be called like that:
var storedExpertises = JSON.parse(localStorage.getItem("explib"));
and not like that:
localStorage.getItem("explib")
Big thanks Sir #Ananthapadmanabhan for your help and advices.
You have enabled CORS for the endpoint http://localhost:4200 on port address 4200. But it seems you are running the angular 6 app separately on local and the request is being made from the port address 6227 , which might be causing the issue since the CORS policy that you have enabled only allows same origin. Try adding the following in CORS :
#CrossOrigin(origins = "http://localhost:6227")
and if you are still having issues with , Cross-Origin Request Blocked (Reason: CORS header ‘Access-Control-Allow-Origin’ missing) then check this post :
CORS policy conflict in Spring boot
Even through you have enabled the CORS. The requests from different ports will not go through. You need to enable HTTP.OPTIONS.

Spring + restful + cors + not func

I am having a problem in my restful service with spring. Even after enabling CORS, I can not connect to my angular application.
#CrossOrigin
public class UsuarioController {
#Autowired
UsuarioService service;
#RequestMapping(method = RequestMethod.GET, value = "/lista_todos_usuarios", produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<Collection<Usuario>> buscaTodosUsuarios() {
Collection<Usuario> usuarios = service.buscaTodosUsuarios();
return new ResponseEntity<>(usuarios, HttpStatus.OK);
}
}
From Enabling Cross Origin Requests for a RESTful Web Service
In your case, I think you need indicate what origin is allowed to access the service.
In the example, the origin is http://localhost:9000. It should correspond to your Angular application.
Enabling CORS
Controller method CORS configuration
So that the RESTful web service will include CORS access control
headers in its response, you just have to add a #CrossOrigin
annotation to the handler method:
src/main/java/hello/GreetingController.java
#CrossOrigin(origins = "http://localhost:9000")
#GetMapping("/greeting")
public Greeting greeting(#RequestParam(required=false, defaultValue="World") String name) {
System.out.println("==== in greeting ====");
return new Greeting(counter.incrementAndGet(), String.format(template, name));
}
As a very simple workaround I could recommend to install CORS extension plugin for Chrome and use it during initial development stages.
If you want a global configuration, you may override method addCorsMappings of WebMvcConfigurerAdapter in your web configuration:
#Configuration
#EnableWebMvc
public class DispatcherContext extends WebMvcConfigurerAdapter {
#Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedMethods("GET", "POST", "PUT", "PATCH", "DELETE", "HEAD");
}
}
Thanks Nikolay, sometimes we miss out on obvious things. Hehehe
in fact, I forgot to annotate the class with #RestController.

How to get a respose from a localhost url exactly http://localhost:8888/

I have two projects setting up Springboot in it, now, I am going to run these two springboot on eclipse, I set up the port 8888 for projectB.
Here is my projectB controller with RequestMapping.
#RequestMapping(value = "test", method = RequestMethod.GET)
public #ResponseBody String test() {
return "testtesttest";
}
I need to call a url from jquery method that url is to read the respose from a controller in projectB.
how can I call this url ??
I tried "http://localhost:8888/test" and "http://127.0.0.1:8888/test"
but I did not get anything from the response.
The error shows up as :
please give me the solution for this
very appreciated.
Add below code in your application's main class. This configures your web mvc cors mapping to allow request from " * "
#SpringBootApplication
public class Application {
#Configuration
public class MyConfiguration {
#Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurerAdapter() {
#Override
public void addCorsMappings(CorsRegistry registry) {
logger.info("Added CORS config");
registry.addMapping("/**").allowedOrigins("*").maxAge(3600);
}
};
}
}
}

How to add CORS headers to the Spring error page rendered by BasicErrorController?

I have a single page client being served by a Spring Boot REST MVC API application (spring boot version 1.5.2).
My app is secured via Auth0 JWT tokens. When things are working, the CORS headers for responses are provided by a ServletFilter that gets configured as part of setting up the security:
protected void configure(HttpSecurity http) throws Exception {
...
http.addFilterBefore(simpleCORSFilter(), Auth0AuthenticationFilter.class);
...
}
This seems to work everywhere I've tested it so far - but one place where it's not working is with the default Spring error page (path "/error", rendered by default by the BasicErrorController class).
When there's an exception thrown in my service methods, the error page works and renders the content I want as JSON in the response body, but the client app can't access the http response body because the response lacks CORS headers.
So the question: "how do I add CORS headers to the error page"?
Should I be removing the CORS filter from my security setup and applying the CORS filter more globally? Where would that be done - I can't find anything relevant in the Spring doccumentation.
Or should I be writing a custom Error controller? The only example of a custom error controller in the documentation just seems to allow you to return a string.
You can define a separate Controller for Error and allow cross origin to it using
#CrossOrigin("*")
Combining Poorvi's answer with Joni Karppinen's custom error controller code gives:
#RestController
public class ErrorController
implements org.springframework.boot.autoconfigure.web.ErrorController
{
private static final String PATH = "/error";
#Autowired private ErrorAttributes errorAttributes;
#Override
public String getErrorPath(){
return PATH;
}
// I guess when time comes to lock down cors header, we could use a spring
// value configuration here to share with corsfilter.
#CrossOrigin("*")
#RequestMapping(value = PATH, produces = "application/json")
public #ResponseBody
ErrorJson error(HttpServletRequest request, HttpServletResponse response){
return new ErrorJson(
response.getStatus(),
getErrorAttributes(request, false) );
}
private Map<String, Object> getErrorAttributes(
HttpServletRequest request,
boolean includeStackTrace
){
RequestAttributes requestAttributes = new ServletRequestAttributes(request);
return errorAttributes.getErrorAttributes(
requestAttributes,
includeStackTrace);
}
}
class ErrorJson {
public Integer status;
public String error;
public String message;
public String timeStamp;
public String trace;
public ErrorJson(int status, Map<String, Object> errorAttributes){
this.status = status;
this.error = (String) errorAttributes.get("error");
this.message = (String) errorAttributes.get("message");
this.timeStamp = errorAttributes.get("timestamp").toString();
this.trace = (String) errorAttributes.get("trace");
}
}
Which seems to do the job for me.

Spring URI PathVariable with file extension not working

I'm having trouble working out why the file extension (.jpg) in the following request is being stripped before calling my controller method:
GET http://blah.com/assets/picture.jpg
I've set the content negotiation to not favour path extensions:
#Configuration
#EnableWebMvc
#ComponentScan(basePackages = { "com.blah" })
public class PlatformWebAppConfig extends WebMvcConfigurerAdapter {
public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
configurer.favorPathExtension(false);
configurer.favorParameter(false);
configurer.useJaf(false);
configurer.defaultContentType(MediaType.APPLICATION_JSON);
}
}
my controller is this:
#Controller
public class FileUploadRestApi {
#RequestMapping(
value = "/assets/{filename}",
method = RequestMethod.GET)
public void downloadFile(HttpServletResponse response,
#PathVariable("filename") String filename,
Principal principal) {
// ERROR: 'filename' has extension stripped !!!!
}
}
I've also tried adding the following to the PlatformWebAppConfig class above with no luck:
#Override
public void configurePathMatch(PathMatchConfigurer matcher) {
matcher.setUseSuffixPatternMatch(true);
matcher.setUseRegisteredSuffixPatternMatch(true);
}
I've tried to debug the issue and I've got as far as seeing ContentNegotiationManagerFactoryBean.afterPropertiesSet is definitely seeing the favorPathExtension setting as false and not setting up a content negotiation strategy (as expected).
Update:
If I change the request mapping to
"/assets/{filename:.+}"
the filename will include the extensions but this does not explain why setting all those configurers did not achieve anything????

Resources