仅在涉及文件上载/下载时阻止跨源请求

问题描述 投票:0回答:1

我有一个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会阻止错误。我错过了什么?

java angular spring-boot spring-web
1个回答
0
投票

我不确定,但我想这个答案会以某种方式帮助你

我曾经遇到过同样的问题,在研究了一些问题之后,我意识到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)中设置一些必需参数。还添加了一些您想要添加的其他参数。

  1. 右键单击浏览器 - >选择检查元素 - >进入网络窗格 - >单击请求的URL - >在新打开的块中,您可以看到请求及其相关内容 - >进入响应标题选项
  2. 在前端代码上添加调试器 - > console.log(“”)
  3. 转到结束点 - >获取资源参数 - >将文件添加为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);
  1. SimpleCORSFilter类 - > doFilter()方法 - >添加
response.setHeader(“Access-Control-Expose-Headers”, “xsrf-token, X-Total-Results, Authorization, Content-type, Content-Disposition”)

你仍然会在评论中提到一些问题,我会为此发送一个演示。

© www.soinside.com 2019 - 2024. All rights reserved.