I'm running a service using Spring and my Angular front-end is getting a 403 with Request Method: OPTIONS when it tries to make a POST request.
Both the Spring service and the Angular app are running locally on my machine. I tried toggling CORS with a Chrome plugin, but that didn't seem to fix the issue.
All my GET requests to the service seem to work alright. I can do the POST request in Postman, so I'm not sure why the angular app can't make the request, but Postman can.
****EDIT****
Response Headers
Allow: GET, HEAD, POST, PUT, DELETE, OPTIONS, PATCH
Content-Length: 20
Date: Sat, 31 Mar 2018 19:15:01 GMT
Request Headers
Accept: */*
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9
Access-Control-Request-Headers: content-type
Access-Control-Request-Method: POST
Connection: keep-alive
Host: localhost:9901
Origin: http://localhost:4200
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.162 Safari/537.36
The simple answer is; “You need to be given the correct access”. Without being given the correct access you'd technically be hacking the server, as it is specifically set up to restrict said access.
For adding a Spring Boot Security to your Spring Boot application, we need to add the Spring Boot Starter Security dependency in our build configuration file. Maven users can add the following dependency in the pom. xml file. Gradle users can add the following dependency in the build.
To fix all CORS issues in an Angular(front end) plus Spring boot(backend) project, add the following Spring component:
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
public class ConfigCtrl implements Filter {
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
final HttpServletResponse response = (HttpServletResponse) res;
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Methods", "POST, PUT, GET, OPTIONS, DELETE");
response.setHeader("Access-Control-Allow-Headers", "Authorization, Content-Type");
response.setHeader("Access-Control-Max-Age", "3600");
if ("OPTIONS".equalsIgnoreCase(((HttpServletRequest) req).getMethod())) {
response.setStatus(HttpServletResponse.SC_OK);
} else {
chain.doFilter(req, res);
}
}
@Override
public void destroy() {
}
@Override
public void init(FilterConfig config) throws ServletException {
}
}
PS for beginners: The name of the class and its location within the Spring app does not matter.
Credit to Ajitesh Kumar.
CORS Request is made by your Frontend to see what are the methods (HTTP Verbs
) that your backed allows. This is usually required for monetary operations e.g., POST
or PUT
which are meant to modify data.
Hence your Frontend will make this call first and your backend needs to respond with allowed methods, you can also restrict specific URIs, then upon successful validation, the target call is made.
This is perfectly normal and angular does this internally so as to not make an unnecessary data request without knowing whether the server will allow.
Here's how you will set it up in Spring
.
//Change/Customize as necessary
@Bean
CorsConfigurationSource corsConfigurationSource() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration corsConfiguration = new CorsConfiguration();
corsConfiguration.addAllowedOrigin("<your origin>");
corsConfiguration.setAllowedMethods(Arrays.asList(
HttpMethod.GET.name(),
HttpMethod.HEAD.name(),
HttpMethod.POST.name(),
HttpMethod.PUT.name(),
HttpMethod.DELETE.name()));
corsConfiguration.setMaxAge(1800L);
source.registerCorsConfiguration("/**", corsConfiguration); // you restrict your path here
return source;
}
If you are also using any custom response headers
from your backend, then you need to allow that as well in the CORS configuration.
As an example
corsConfiguration.addAllowedHeader("*");
corsConfiguration.addExposedHeader("header1");
corsConfiguration.addExposedHeader("header2");
If we are talking about SpringBoot, presumably latest or at least recent version, then we can simply use the @CrossOrigin
annotation next to the @RestController
annotation in our controller classes. It is available since Spring ver. 4.2
For example:
@RestController
@CrossOrigin
@RequestMapping("/api")
public class MyObjectsController {
private final MyObjectsService service;
@Autowired
public MyObjectsController(MyObjectsService service) {
this.service = service;
}
@GetMapping("/version")
public Version getVersion() {
return service.getVersion();
}
@PostMapping("/objects")
public ObjectResource createObject(@RequestBody @Valid ObjectData data) {
return service.createObject(data);
}
@GetMapping("/objects/{id}")
public ObjectResource getObject(@PathVariable String id) {
return service.getObjectById(id);
}
}
Benefits:
Referer
header is analyzed)See also:
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With