I have a SpringBoot Backend with Spring Security Enabled in the default configuration (nothing changed there).
I have following Rest Controller and Post Mapping:
@RestController
public class MyController {
@PostMapping(value = "/sm/resrc/pth")
public Integer postSomething(@RequestParam String someValue,@RequestParam String userId){
System.out.println(String.format("SomeValue: %s from userid %s",someValue,userId));
return 0;
}
}
- Creating a Post request from the following form works fine:
<form method="post" th:action="@{/sm/resrc/pth}">
<input type="text" name="someValue">
<input type="text" name="userId">
<input type="hidden" name="_csrf" value="${_csrf.token}" />
<div><input type="submit" value="Send" /></div>
</form>
It does even work without the hidden cors value.
- However I need to create a post request from JavaScript, which doesn't work. The SpringBoot application is running at localhost:8080. I thought, the credentials parameter 'include' is used for including the required authentication headers, which the user already entered successfully to open the given page. Is this correct? I also changed the value of 'mode'. I tried 'cors', 'same-origin' and 'no-cors'. It just does't work. I event don't understand why cors is a problem anyway as I am requesting a resource from the same origin. It didn't even work after adding the Authorization header manually to the request without using the credentials parameter.As you can see in the image I always get the 403 status. What is wrong with my request? What am I missing?
let data = {
"some":"abc",
"values":this.localDescription,
"userId":userId
};
fetch("sm/resrc/pth",
{
method: 'POST',
credentials: 'include',
mode: 'cors',
body: data
}
).then(response => console.log(response));
CodePudding user response:
I've found the same problem doing a login example with jax-rs. In my case the problem was that when add the 'credentials': 'include' to the request, on the side of the Rest Service API, need configure in the CORS Filter the header from:
response.addHeader("Access-Control-Allow-Origin", "*");
to:
res.addHeader("Access-Control-Allow-Origin", "http://localhost");
Where "http://localhost is the origin of my request.
I've found information about it in this post: No 'Access-Control-Allow-Origin' header is present on the requested resource—when trying to get data from a REST API
CodePudding user response:
CORS is a security feature; So you probably don't want to disable or bypass it. I struggled a bit to find out, how to include the headers correctly but finally found the solution. That's how I solved it:
In the first step I added the expected CSRF-Header-name and the token itself to the metadata of the generated html file. In spring using the templating framework thyemleaf it looks like following:
<html lang="en">
<head>
<meta name="_csrf_header_name" th:content="${_csrf.headerName}"/>
<meta name="_csrf_token" th:content="${_csrf.token}"/>
</head>
.
.
.
</html>
Which results in something like that:
<meta name="_csrf_header_name" content="X-CSRF-TOKEN">
<meta name="_csrf_token" content="14d98c88-8643-1234-5678-39473aa7890e">
In the fetch request, the CSRF Header is built from the token and the correct Header-name (which are read from the meta tags) just as expected from the server.
getCsrfToken(){
return document.querySelector('meta[name=_csrf_token]').content;
}
getCsrfTokenName(){
return document.querySelector('meta[name=_csrf_header_name]').content;
}
let csrfToken = this.getCsrfToken();
let csrfTokenName = this.getCsrfTokenName();
fetch('sm/resrc/pth', {
method:'post',
headers: new Headers([[csrfTokenName, csrfToken]])
}).then(res =>{console.log(res);});}