仅在涉及文件上载/下载时阻止跨源请求
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了仅在涉及文件上载/下载时阻止跨源请求相关的知识,希望对你有一定的参考价值。
我有一个Angular应用程序,它向Spring 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;
}
这个与Spring Boot应用程序联系的Angular服务:
@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会阻止错误。我错过了什么?
我不确定,但我想这个答案会以某种方式帮助你
我曾经遇到过同样的问题,在研究了一些问题之后,我意识到spring boot为CORS起源提供了一些更高级别的安全性,以限制CROSS SITE ATTACK。
我们稍后再讨论,首先我们谈到这一点,
在使用任何CORS源时,您在SimpleCORSFilter类中编写的代码主要负责标头级安全性。
为验证这一点,请使用inspect元素(Point-1)检查响应头。
检查您执行前端代码所需或用于的每个头元素(根据您之前提到的Anguler代码)。下载文件需要一些内容类型,内容处理等参数。我想你没有正确提及它或不按照弹簧启动标准使用(Point-2)。
如果缺少此参数然后将其发送到您的响应中,我不确定您的代码是否正常工作,但是当您使用spring boot将多部分文件作为Resource发送时,这是一个更好的做法,每个标题参数都是如此
content-type:文件MIME类型,内容 - 处置:您执行的文件名和操作:attachment / inline(Point-3)。
在某些情况下,这个所有参数仍然无法下载(我面对),
解决方案是将该参数添加为响应,但不允许它们通过CORS源访问。
为此,您需要在“Access-Control-Expose-Headers”(Point-4)中设置一些必需参数。还添加了一些您想要添加的其他参数。
- 右键单击浏览器 - >选择检查元素 - >进入网络窗格 - >单击请求的URL - >在新打开的块中,您可以看到请求及其相关内容 - >进入响应标题选项
- 在前端代码上添加调试器 - > console.log(“”)
- 转到结束点 - >获取资源参数 - >将文件添加为OutputStream - >将其作为ResponseEntity发送
Path path = Paths.get(<directory-path>).normalize();
Path filePath = path.resolve(fileName).normalize();
Resource resource = new UrlResource(filePath.toUri());
Return ResponseEntity.ok
.contentType(MediaType.<MIME-Type>)
.header(HttpHeaders.CONTENT_DISPOSITION, “attachment; filename=””+ resource.filename())
.body(resource);
- SimpleCORSFilter类 - > doFilter()方法 - >添加
response.setHeader(“Access-Control-Expose-Headers”, “xsrf-token, X-Total-Results, Authorization, Content-type, Content-Disposition”)
你仍然会在评论中提到一些问题,我会为此发送一个演示。
以上是关于仅在涉及文件上载/下载时阻止跨源请求的主要内容,如果未能解决你的问题,请参考以下文章
跨源请求在 tomcat 8 中被阻止,HTTP 状态代码为 403
Angular2,REST 服务 POST 调用错误:“跨源请求被阻止”
跨源请求被阻止的 CORS - 使用角度 cli 解决 [仅限开发人员] [重复]