我有一个Angular应用程序,它向Sping Boot RESTful API发出请求。出于开发目的,我在Spring Boot中设置了一个非常宽松的CORS策略(请注意,对于任何阅读本文并可能复制或粘贴的人,这些并不意味着是安全的生产值)。
@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);
}
}
使用它的@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服务与Sping 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' }
);
}
}
虽然我以前也遇到过类似的问题,但我认为Java代码中的CORSFilter可以防止这个错误。
1条答案
按热度按时间368yc8dk1#
我不确定,但我想这个答案在某种程度上对你有帮助
我曾经遇到过同样的问题,在研究了一些要点之后,我意识到Sping Boot 为CORS源提供了一些扩展级别的安全性,以限制跨站攻击。
我们稍后再讨论,先说重点,
您在SimpleCORSFilter类中编写的代码主要负责在使用任何CORS源时的头级别安全性。
为了验证这一点,请使用inspect元素(Point - 1)检查您的响应头。
检查每个头元素,你需要或用于执行你的前端代码(根据你前面提到的Anguler代码)。一些参数,如content-type,content-disposition是下载文件所必需的。我想你没有正确地提到它,或者没有按照Sping Boot 标准使用(Point - 2)。
如果缺少此参数,请在响应中发送它,我不确定您的代码是否正常工作,但当您使用spring Boot 时,将多部分文件作为Resource发送,每个头参数如下
内容类型:文件MIME类型,内容-处置:文件名和执行的操作:attachment / inline(点-3)。
在某些情况下,这所有的参数都在那里,你仍然无法下载(我面对),
解决方案是将该参数添加为响应,但不允许它们通过CORS源访问。
为此,您需要在“Access-Control-Expose-Headers”(点4)中设置一些必需的参数。还可以添加一些您想要添加的其他参数。
1.右键单击浏览器-〉选择检查元素-〉进入网络窗格-〉单击请求的URL -〉在新打开的块中,您可以看到请求及其相关内容-〉进入响应头选项
1.在前端代码上添加调试器-〉console.log(“”)
1.进入终点-〉Take Resource param -〉Add file as OutputStream -〉Send it as ResponseEntity
你仍然面临着一些问题,在评论中提到,我会送一个演示。