Search code examples
angularspring-bootspring-mvcspring-securitycors

CORS issue during file upload and download in [framework/library]


Description

I'm encountering a CORS (Cross-Origin Resource Sharing) issue specifically when performing file upload and download operations in my angular-springboot3 application. The CORS problem occurs only with these file-related requests, while other API requests work fine.

Problem

When attempting to upload or download files, I receive the following error message in the browser console:

Acess to XMLHttpRequest at 'http://localhost:8081/api/v1/download-excel' from origin 'http://localhost:4200' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.

Additional Information:

  • I have already set the appropriate @CrossOrigin annotation in the backend controller for the file upload/download endpoints.
  • I have verified that the CORS issue is specific to file upload and download requests, as other API requests in the application are not affected.
  • I have tried adding the withCredentials: true option in the frontend http.post() method, but it did not resolve the CORS issue.
  • The server is properly configured with CORS headers and allows requests from the frontend origin.

Code snippets

Front End :

    uploadExcelFile(file: File): Observable<any> {
        return this.http.post(this.API_URL+'upload-excel', file);
    }

    downloadExcelFile(toDownload: any[]): Observable<HttpResponse<Blob>> {
        var idList: number[] = []
        toDownload.forEach((value)=> idList.push(value.id))
        const headers = new HttpHeaders({
            'Content-Type': 'application/octet-stream',
        });

        const params = new HttpParams().set('ids', idList.join(','));

        return this.http.post<Blob>(this.API_URL+'download-excel',params, {
            headers: headers,
            observe: 'response',
            responseType: 'blob' as 'json'
        }).pipe(
            catchError((error: any) => {
                console.error('Error occurred during file download:', error);
                throw error;
            })
        );
    }

Back end:

@CrossOrigin(origins = "http://localhost:4200")
@RequestMapping(path = "/upload-excel", method = RequestMethod.POST)
public ResponseEntity<?> uploadExcelFile(@RequestParam("file") MultipartFile file) {
        ExcelUploader helper = new ExcelUploader();
        List<Entity> toAdd = helper.uploadFromExcel(file);
        navireRepository.saveAll(toAdd);
        return new ResponseEntity<>("File uploaded successfully", HttpStatus.OK);
}
    

@CrossOrigin(origins = "http://localhost:4200")
@RequestMapping(path = "/download-excel", method = RequestMethod.GET)
public ResponseEntity<byte[]> downloadExcelFile(@RequestBody List<Navire> toDownload) throws IOException {
        ExcelDownloader helper = new ExcelDownloader();
        List<Navire> toDownload = new ArrayList<>();
        for (Long id : ids) {
            toDownload.add(repository.getReferenceById(id));
        }

        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
        headers.set("Access-Control-Allow-Origin", "*");
        headers.setContentDispositionFormData("attachment", "entity.xlsx");

        byte[] bytes = helper.downloadToExcel(toDownload);

        return new ResponseEntity<>(bytes, headers, HttpStatus.OK);
    
}

hers my security configuration too

@Configuration
@EnableWebSecurity
@RequiredArgsConstructor
public class SecurityConfiguration {

    private final JwtAuthenticationFilter jwtAuthFilter;
    private final AuthenticationProvider authenticationProvider;
    private final LogoutHandler logoutHandler;

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
                .csrf()
                .disable()
                .cors()
                .disable()
                .authorizeHttpRequests()
                .requestMatchers("/api/v1/**", "/swagger-ui/**", "/v3/api-docs/**")
                .permitAll()
                .anyRequest()
                .authenticated()
                .and()
                .sessionManagement()
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
                .authenticationProvider(authenticationProvider)
                .addFilterBefore(jwtAuthFilter, UsernamePasswordAuthenticationFilter.class)
                .logout()
                .logoutUrl("/api/v1/auth/logout")
                .addLogoutHandler(logoutHandler)
                .logoutSuccessHandler((request, response, authentication) -> SecurityContextHolder.clearContext())
        ;

        return http.build();
    }


}

I would greatly appreciate any insights or suggestions on how to resolve this CORS issue specifically related to file upload and download feature with Spring boot 3. Thank you in advance for your help!


Solution

  • Solution It all went smoothly when I added a global cors configuration like so

        @Bean
        public FilterRegistrationBean<CorsFilter> corsFilter() {
            UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
            CorsConfiguration config = new CorsConfiguration();
            config.addAllowedOrigin("http://localhost:4200");
            config.addAllowedHeader("*");
            config.addAllowedMethod("*");
            source.registerCorsConfiguration("/**", config);
            FilterRegistrationBean<CorsFilter> bean = new FilterRegistrationBean<>(new CorsFilter(source));
            bean.setOrder(0);
            return bean;
        }