Cross-Origin Request блокируется только при участии файловых загрузок / загрузок - PullRequest
0 голосов
/ 26 октября 2018

У меня есть приложение 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-коде предотвратит ошибку. Чего мне не хватает?

1 Ответ

0 голосов
/ 14 апреля 2019

Я не уверен, но я полагаю, что этот ответ поможет вам как-то

Однажды я столкнулся с той же проблемой, и после изучения некоторых моментов я понимаю, что весенняя загрузка обеспечивает некоторый расширенный уровень безопасности для источников CORS,ограничить CROSS SITE ATTACK.

Мы обсудим это позже, сначала перейдем к вопросу,

Код, который вы написали в классе SimpleCORSFilter, в основном отвечает за безопасность на уровне заголовка, когда вы работаете с любымпроисхождения CORS.

Для проверки проверьте заголовок ответа, используя элемент проверки (Точка - 1).

Проверьте каждый элемент заголовка, который вы потребовали или использовали для выполнения вашего кода переднего плана (код Anguler, как вы упоминали ранее).Некоторые параметры, такие как content-type, content-disposition требуются для загрузки файла.Я полагаю, вы не упоминаете это должным образом или не используете в соответствии со стандартами пружинной загрузки (пункт 2).

Если этот параметр отсутствует, отправьте его в своем ответе, я не уверен, что ваш код работает или нет, но лучше работать, когда ваша работа с весенней загрузкой отправляет ваш файл из нескольких частей в качестве ресурса с каждым заголовкомпараметр типа

тип содержимого: тип файла MIME, содержимое - расположение: имя файла и выполняемое вами действие: вложение / встроенный (точка - 3).

В некоторых случаях это параметр allесли вы все еще не можете загрузить (с чем я сталкиваюсь),

Решение состоит в том, что вы добавляете этот параметр в качестве ответа, но не разрешаете им доступ по источнику CORS.

Для этого вам необходимо установить некоторые обязательные параметры в «Access-Control-Expose-Headers» (Точка - 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);
Класс SimpleCORSFilter -> метод doFilter () -> add
response.setHeader(“Access-Control-Expose-Headers”, “xsrf-token, X-Total-Results, Authorization, Content-type, Content-Disposition”)

Тем не менее вы столкнетесь с проблемой упоминания в комментарии, и я пришлю для этого одну демонстрацию.

...