I have created a small website that I would like to provide. I use Spring Boot 3 as backend and Angular 15 as frontend. Now I have like many the problem that my frontend can't communicate with my backend because of Cors. I have looked at many sites on the internet and tried to solve the problem myself but unfortunately without success (https://rajendraprasadpadma.medium.com/what-the-cors-ft-spring-boot-spring-security-562f24d705c9 , Spring Boot : CORS Issue).
Here you can see my attempts:
Attempt 1: Adding a Bean in my Security Config
@Bean
CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(Arrays.asList("*"));
configuration.setAllowedMethods(Arrays.asList("*"));
configuration.setAllowedHeaders(List.of("*"));
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
Attempt 2: Adding another bean in my Security Config
@Bean
CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(Arrays.asList("*"));
configuration.setAllowedMethods(Arrays.asList("*"));
configuration.setAllowCredentials(true);
//the below three lines will add the relevant CORS response headers
configuration.addAllowedOrigin("*");
configuration.addAllowedHeader("*");
configuration.addAllowedMethod("*");
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
Attempt 3: Adding @CrossOrigin to each of my controller class
import org.springframework.web.bind.annotation.CrossOrigin;
@RestController
@RequestMapping("/api/v1/productcategory")
@CrossOrigin
public class ProductCategoryController {
@Autowired
ProductCategoryService productCategoryService;
@GetMapping
public ResponseEntity<List<ProductCategory>> get(){
return ResponseEntity.ok(productCategoryService.getAll());
}
@PostMapping
public ResponseEntity<String> post(){
return ResponseEntity.ok("POST: Hello Management");
}
@PutMapping
public ResponseEntity<String> put(){
return ResponseEntity.ok("PUT: Hello Management");
}
@DeleteMapping
public ResponseEntity<String> delete(){
return ResponseEntity.ok("DELETE: Hello Management");
}
Attempt 4: Adding the Cors property to my FilterChain
@Override
protected void doFilterInternal(@NonNull HttpServletRequest request,
@NonNull HttpServletResponse response,
@NonNull FilterChain filterChain) throws ServletException, IOException {
response.setHeader("Access-Control-Allow-Origin", request.getHeader("Origin"));
response.setHeader("Access-Control-Allow-Credentials", "true");
response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers", "Content-Type, Accept, X-Requested-With, remember-me");
final String authHeader = request.getHeader("Authorization");
final String jwt;
final String userEmail;
if(authHeader == null || !authHeader.startsWith("Bearer ")) {
filterChain.doFilter(request, response);
return;
}
jwt = authHeader.substring(7);
userEmail = jwtService.extractUsername(jwt);
if(userEmail !=null && SecurityContextHolder.getContext().getAuthentication() == null) {
UserDetails userDetails = this.userDetailsService.loadUserByUsername(userEmail);
var isTokenValid = tokenRepository.findByToken(jwt)
.map(t -> !t.isExpired() && !t.isRevoked())
.orElse(false);
if(jwtService.isTokenValid(jwt, userDetails) && isTokenValid) {
UsernamePasswordAuthenticationToken authToken = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
authToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
SecurityContextHolder.getContext().setAuthentication(authToken);
}
}
filterChain.doFilter(request, response);
}
To this is to say what I use as authentication and authorization a JWT token.
In my Angular app, I have an HttpIntercept:
import { Injectable } from '@angular/core';
import {
HttpRequest,
HttpHandler,
HttpEvent,
HttpInterceptor,
HttpResponse,
HttpErrorResponse
} from '@angular/common/http';
import { Observable, throwError } from 'rxjs';
import { catchError } from 'rxjs/operators';
@Injectable()
export class RequestInterceptorInterceptor implements HttpInterceptor {
constructor() {}
intercept(request: HttpRequest<unknown>, next: HttpHandler): Observable<HttpEvent<unknown>> {
if (request.method !== 'OPTIONS') {
const jwtString = localStorage.getItem('jwt');
const jwtToken = jwtString ? JSON.parse(jwtString)?.jwt as string : '';
const authorizationHeader = `Bearer ${jwtToken}`;
request = request.clone({ headers: request.headers.set('Authorization', authorizationHeader)});
}
return next.handle(request).pipe(
catchError((error: HttpErrorResponse) => {
// Hier kannst du den Fehler abfangen und entsprechende Aktionen ausführen
if (error.status === 0 && error.statusText === 'Unknown Error') {
console.log('Es ist ein CORS-Fehler aufgetreten');
// Weitere Aktionen ausführen ...
}
// Wirf den Fehler weiter, um ihn an den Aufrufer weiterzugeben
return throwError(error);
})
);
}
}
Here are my error logs:
What amazes me is that I can't even get through the preflight with my attempts.
Does anyone have any idea what I'm doing wrong or what I can still try. So that back- and frontend communicate with each other?
Thanks in advance