I'm trying to create a user administration API for my web app. When I send an API call from my frontend to my backend, a cors error occurs. How can the cors problem be solved? I've read a lot of threads, but I haven't made any progress.
Error after createUser() API call
Access to XMLHttpRequest at 'http://localhost:8080/user/create'
from origin 'http://localhost:4200' has been blocked by CORS policy:
Response to preflight request doesn't pass access control check:
Redirect is not allowed for a preflight request.
Angular header.config.ts
export const HTTP_OPTIONS = {
headers: new HttpHeaders({
'Content-Type': 'application/json',
'Access-Control-Allow-Credentials' : 'true',
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': 'GET, POST, PATCH, DELETE, PUT, OPTIONS',
'Access-Control-Allow-Headers': 'Content-Type, Access-Control-Allow-Headers, Authorization, X-Requested-With',
})
};
Angular rest-user.service.ts
public createUser() {
return this.httpClient.post(this.USER_ENDPOINT + 'create', HTTP_OPTIONS);
}
SpringConfig.class
@Configuration
@EnableWebMvc
public class SpringConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**");
}
}
SpringSecurityConfig.class
@Configuration
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().anyRequest().authenticated()
.and().oauth2Client()
.and().oauth2Login();
}
}
UserRestController.class
@PostMapping("/user/create")
@ResponseBody
@ResponseStatus(HttpStatus.CREATED)
public void createUser(Principal principal) throws UserAlreadyExistsException {
userServiceFacadeImpl.createUser(principal.getName());
}
Network Message
UPDATE 20.06.19
private createUser() {
const headersObject = new HttpHeaders();
this.oktaAuth.getAccessToken().then( (value) => {
headersObject.append('Authorization', 'Bearer ' + value);
headersObject.append('Content-Type', 'application/json');
const httpOptions = {
headers: headersObject
};
this.httpClient.post('http://localhost:8080/user/' + 'create', null, httpOptions);
});
}
Simple Requests. Another way to avoid Preflight requests is to use simple requests. Preflight requests are not mandatory for simple requests, and according to w3c CORS specification, we can label HTTP requests as simple requests if they meet the following conditions. Request method should be GET , POST , or HEAD .
The CORS request requires preflight, preflighting could not be performed. There are a couple of reasons why preflighting might fail: A cross-site request has previously been performed that already did a preflight, and doing the preflight again is not permitted. Make sure your code only preflights once per connection.
A CORS preflight request is a CORS request that checks to see if the CORS protocol is understood and a server is aware using specific methods and headers. It is an OPTIONS request, using three HTTP request headers: Access-Control-Request-Method , Access-Control-Request-Headers , and the Origin header.
The CORS behavior, commonly termed as CORS error, is a mechanism to restrict users from accessing shared resources. This is not an error but a security measure to secure users or the website which you are accessing from a potential security bleach.
You may need to config the CORS at Spring Boot side. Please add below class in your Project.
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
@EnableWebMvc
public class WebConfig implements Filter,WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**");
}
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) {
HttpServletResponse response = (HttpServletResponse) res;
HttpServletRequest request = (HttpServletRequest) req;
System.out.println("WebConfig; "+request.getRequestURI());
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Methods", "POST, PUT, GET, OPTIONS, DELETE");
response.setHeader("Access-Control-Allow-Headers", "Content-Type, Access-Control-Allow-Headers, Authorization, X-Requested-With,observe");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Credentials", "true");
response.setHeader("Access-Control-Expose-Headers", "Authorization");
response.addHeader("Access-Control-Expose-Headers", "responseType");
response.addHeader("Access-Control-Expose-Headers", "observe");
System.out.println("Request Method: "+request.getMethod());
if (!(request.getMethod().equalsIgnoreCase("OPTIONS"))) {
try {
chain.doFilter(req, res);
} catch(Exception e) {
e.printStackTrace();
}
} else {
System.out.println("Pre-flight");
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Methods", "POST,GET,DELETE,PUT");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers", "Access-Control-Expose-Headers"+"Authorization, content-type," +
"USERID"+"ROLE"+
"access-control-request-headers,access-control-request-method,accept,origin,authorization,x-requested-with,responseType,observe");
response.setStatus(HttpServletResponse.SC_OK);
}
}
}
UPDATE:
To append Token to each request you can create one Interceptor as below.
import { Injectable } from '@angular/core';
import { HttpEvent, HttpHandler, HttpInterceptor, HttpRequest } from '@angular/common/http';
import { Observable } from 'rxjs';
@Injectable()
export class AuthInterceptor implements HttpInterceptor {
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
const token = window.localStorage.getItem('tokenKey'); // you probably want to store it in localStorage or something
if (!token) {
return next.handle(req);
}
const req1 = req.clone({
headers: req.headers.set('Authorization', `${token}`),
});
return next.handle(req1);
}
}
Example
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