У меня есть приложение Angular, которое делает запрос к Spring Boot RESTful API. В целях разработки я установил свободную политику CORS в моем Spring Boot (обратите внимание, что при любом чтении этого и, возможно, копировании или вставке, это не означает, что это безопасные производственные значения).
@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
public class SimpleCORSFilter implements Filter {
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
throws IOException, ServletException {
HttpServletResponse response = (HttpServletResponse) res;
HttpServletRequest request = (HttpServletRequest) req;
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Methods", "POST, GET, PUT, OPTIONS, DELETE, PATCH");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers",
"Origin, X-Requested-With, Content-Type, Accept, xsrf-token, authorization");
response.setHeader("Access-Control-Expose-Headers", "Location");
response.addHeader("Access-Control-Expose-Headers", "xsrf-token");
if ("OPTIONS".equalsIgnoreCase(request.getMethod())) {
response.setStatus(HttpServletResponse.SC_OK);
} else {
chain.doFilter(req, res);
}
}
A @Configuration
класс, который его потребляет:
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private PasswordEncoder passwordEncoder;
@Autowired
private SimpleCORSFilter corsFilter;
@Bean
@Override
protected AuthenticationManager authenticationManager() throws Exception {
return super.authenticationManager();
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.addFilterBefore(corsFilter, ChannelProcessingFilter.class).authorizeRequests().antMatchers("/admin/**")
.hasAnyAuthority("ROLE_ADMIN").antMatchers(HttpMethod.GET, "/public").permitAll().and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and().httpBasic()
.realmName("test").and().csrf().disable();
}
}
Как правило, связь между приложениями работает просто найти. Я могу получить и опубликовать данные JSON без проблем. Однако всякий раз, когда я пытаюсь либо загрузить изображение, либо запустить какой-то код, который должен загружать файл, я получаю следующую ошибку в консоли браузера (Firefox):
Запрос на перекрестное происхождение заблокирован: одна и та же политика происхождения запрещает чтение
удаленный ресурс на http://localhost:8092/report/csv/detail.
(Причина: запрос CORS не выполнен).
Конечная точка контроллера (Java):
@RequestMapping("/csv/detail")
public ResponseEntity<?> getDetailedCSV(@RequestBody ReportRequestDTO dto) {
HttpHeaders headers = new HttpHeaders();
byte[] contents;
try {
contents = IOUtils.toByteArray(new FileInputStream(reportService.getPDFSummary((dto))));
headers.setContentType(MediaType.parseMediaType("application/pdf"));
headers.setCacheControl("must-revalidate, post-check=0, pre-check=0");
ResponseEntity<byte[]> response = new ResponseEntity<byte[]>(contents, headers, HttpStatus.OK);
return response;
} catch (FileNotFoundException ex) {
return new ResponseEntity<>(ex.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR);
} catch (IOException ex) {
return new ResponseEntity<>(ex.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR);
}
}
Метод getPDFSummary:
@Override
public String getPDFSummary(ReportRequestDTO req) {
String outputName = outDir + UUID.randomUUID().toString() + ".pdf";
List<SummaryReport> rows = new ArrayList<>();
if (req.getStatusType() == ReportStatus.ALL) {
rows = summaryRepo.getSummaryReportAllStatus(req.getPropertyIDs(), req.getItemIDs(), req.getStart(),
req.getEnd());
} else {
boolean isOpen = req.getStatusType() == ReportStatus.OPEN;
rows = summaryRepo.getSummaryReport(isOpen, req.getPropertyIDs(), req.getItemIDs(), req.getStart(),
req.getEnd());
}
String html = convertRepsToHtml(rows);
PdfConverterExtension.exportToPdf(outputName, html, "", options);
return outputName;
}
Это служба Angular, которая связывается с приложением Spring Boot:
@Injectable()
export class ReportService {
private baseEndpoint: String = 'http://localhost:8092';
constructor(private http: HttpClient) {}
public getReport(req: ReportRequestModel): Observable<Blob> {
return this.http.post(
`${this.baseEndpoint}/report/${req.exportType}`,
req,
{ responseType: 'blob' }
);
}
}
Хотя раньше я сталкивался с подобными проблемами, я предполагал, что CORSFilter в моем Java-коде предотвратит ошибку. Чего мне не хватает?