我正在尝试为我的网站实施Content-Security-Policy-Report-Only标头。
为了做到这一点,我需要一个接受浏览器POST-Request的控制器 - 它将以JSON的形式发送有关违规的数据。但是,此请求似乎将内容类型指定为application/csp-report
而不是application/json
(旁注:为什么地狱?)。
这显然会导致Spring拒绝请求 - 似乎@RequestBody
的使用使spring只接受Content-Type "application/json"
的请求。
即使我专门将consumes
注释的值@RequestMapping
设置为application/csp-report
,它仍然不接受请求。
我已经使用过滤器来使用HttpServletRequestWrapper
包装请求 - 这似乎是修改请求行为的常用方法。
我已经覆盖了所有这些方法:getContentType()
,getHeader(String)
,getHeaders(String)
以返回“application / json”。
但是请求仍然没有通过。
答案 0 :(得分:3)
根据@RequestBody
注释的文档,
请求的主体通过HttpMessageConverter传递,以根据请求的内容类型解析方法参数
这意味着Spring Framework定义了一个专用API,用于定义某些MediaType在用作REST端点的参数时如何转换为某些Java类型。
Here是一篇很好的文章,展示了这些功能。
如果您的媒体格式可以映射到各自的媒体格式,那么您可以配置和使用大量内置Spring转换器。特别针对您的情况,您应该查看spring.converter.json包中提供的转换器之一。在最简单的情况下,使其工作应该如下:
HttpMessageConverter converter = new <JsonConverterOfYourChoice>(JsonMapper);
converter.getSupportedMediaTypes().add(new MediaType("application", "csp-report"));
然后将这样的转换器注册到弹簧的配置中。
其他可用的转换器类型包括:
最后,如果以上都不适合您,您可以制作并注册自己的HttpMessageConverter实现。
答案 1 :(得分:1)
将M. Prokhorov's answer构建为一个完整的代码段,这段代码可以让我在Spring Boot中添加application/csp-report
作为JSON消息转换器(使用Jackson):
@Bean
public WebMvcConfigurer webMvcConfigurer() {
return new WebMvcConfigurerAdapter() {
@Override
public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
super.extendMessageConverters(converters);
final List<MediaType> cspReportMediaTypes =
Collections.singletonList(new MediaType("application", "csp-report"));
final HttpMessageConverter<Object> cspReportConverter =
new MappingJackson2HttpMessageConverter() {
@Override
public List<MediaType> getSupportedMediaTypes() {
return cspReportMediaTypes;
}
};
converters.add(cspReportConverter);
}
};
}
答案 2 :(得分:0)
其他答案可以帮助我弄清楚@ResponseBody
的情况。
CSP报告仍然相对较新,并且在浏览器之间还不够标准化:
CSP2规范指出,CSP报告请求需要使用 application / csp-report的内容类型标头。在我的样本中 观察到四个不同的内容类型标头:
application/x-www-form-urlencoded application/json application/csp-report application/json; charset=UTF-8
What to Expect When Expecting Content Security Policy Reports
因此,接受任何一种内容类型的替代方法是直接从HttpServletRequest
读取输入流,而不是将@ReponseBody
与消息转换器一起使用。
例如,在科特林:
@PostMapping(path = [CSP_REPORT_URL])
fun reportFrontendError(
request: HttpServletRequest
): ResponseEntity<Void> {
val body = request.inputStream.bufferedReader().use { it.readText() }
// ...
return ResponseEntity(HttpStatus.OK)
}