Reputation: 1704
I have built a RestController, which should help manage tags in a web application. I will be calling all of the methods through AJAX (using JQuery), but Spring-Boot's default Security results in the following (when calling from Postman):
{ "timestamp": 1438800538949, "status": 403, "error": "Forbidden", "message": "Invalid CSRF Token 'null' was found on the request parameter '_csrf' or header 'X-CSRF-TOKEN'.", "path": "/tag/add" }
What is the best way to get the CSRF token to do the calls from JQuery? I assume it's better than to disable it. What about when using it from PostMan?
This is the code of the controller:
@RestController
public class TagController {
@Autowired
private TagService tagService;
@RequestMapping(name = "/tag/list", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<TagList> getTagList() {
TagList result = new TagList(tagService.list());
return new ResponseEntity<TagList>(result, HttpStatus.OK);
}
@RequestMapping(name = "/tag/add", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<?> addTag(@RequestBody AlterTagForm form) {
try {
tagService.addTag(form.getArticleId(), form.getTagName());
return new ResponseEntity<>(HttpStatus.ACCEPTED);
} catch (EntityNotFoundException ex) {
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
}
}
@RequestMapping(name = "/tag/remove", produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<?> removeTag(@RequestBody AlterTagForm form) {
try {
tagService.removeTag(form.getArticleId(), form.getTagName());
return new ResponseEntity<>(HttpStatus.ACCEPTED);
} catch (EntityNotFoundException ex) {
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
}
}
}
Upvotes: 0
Views: 2495
Reputation: 2370
First, you need to include the csrf token within your html:
<meta name="_csrf" id="_csrf" th:content="${_csrf.token}"/>
<meta name="_csrf_header" id="_csrf_header" th:content="${_csrf.headerName}"/>
you can do it in the form too, like this:
<input type="hidden"
name="${_csrf.parameterName}"
value="${_csrf.token}"/>
but i prefer to do that in the meta, because that is in the header and i have this for every template with a form (i use thymeleaf, fragments etc.)
Second, you need to modify your ajax call:
var csrfToken = $('#_csrf').attr("content");
var csrfHeader = $('#_csrf_header').attr("content");
$.ajax({
url : '/tag/remove',
type: 'POST',
data: ({ id: id }),
beforeSend: function(xhr){
xhr.setRequestHeader(csrfHeader, csrfToken);
}
}).done(function(data, textStatus, jqXHR) {
alert('finish');
});
To set the requestHeader
is the most important of this.
PS: Sometimes it can be happen that the csrf header
is null for this you can easily replace this:
var csrfHeader = $('#_csrf_header').attr("content")
with that:
var csrfHeader = 'X-CSRF-TOKEN';
Upvotes: 1