【问题标题】:"415 Unsupported Media Type" for Content-Type "application/csp-report" in ASP.NET CoreASP.NET Core 中 Content-Type“application/csp-report”的“415 Unsupported Media Type”
【发布时间】:2020-05-05 18:03:28
【问题描述】:

我有一个内容安全策略导致 Chrome 发布报告,但接收报告的操作返回“415 Unsupported Media Type”。我知道这是因为该帖子的 Content-Type 为“application/csp-report”。如何在 Core 3.1 中将其添加为允许的内容类型(基本上只是 json)。

动作

// https://anthonychu.ca/post/aspnet-core-csp/
[HttpPost][Consumes("application/csp-report")]
public IActionResult Report([FromBody] CspReportRequest request)
{
    return Ok();
}

模型的缩减版

public class CspReportRequest
{
    [JsonProperty(PropertyName = "csp-report")]
    public CspReport CspReport { get; set; }
}

public class CspReport
{
    [JsonProperty(PropertyName = "document-uri")]
    public string DocumentUri { get; set; }
}

【问题讨论】:

    标签: c# asp.net-core asp.net-core-3.1


    【解决方案1】:

    以下示例显示了如何为 SystemTextJsonInputFormatter 添加支持以处理其他媒体类型:

    services.AddControllers(options =>
    {
        var jsonInputFormatter = options.InputFormatters
            .OfType<SystemTextJsonInputFormatter>()
            .Single();
    
        jsonInputFormatter.SupportedMediaTypes.Add("application/csp-report");
    });
    

    这是一个两步过程:

    1. 查询已配置的输入格式化程序列表以找到SystemTextJsonInputFormatter
    2. application/csp-report 添加到其现有的受支持媒体类型列表(application/jsontext/jsonapplication/*+json)。

    如果您使用 Json.NET 而不是 System.Text.Json,则方法类似

    services.AddControllers(options =>
    {
        var jsonInputFormatter = options.InputFormatters
            .OfType<NewtonsoftJsonInputFormatter>()
            .First();
    
        jsonInputFormatter.SupportedMediaTypes.Add("application/csp-report");
    })
    

    有两个小区别:

    1. 类型是NewtonsoftJsonInputFormatter,而不是SystemTextJsonInputFormatter
    2. 集合中有两个此类型的实例,因此我们以第一个为目标(有关详细信息,请参阅this answer)。

    请参阅 ASP.NET Core 文档中的 Input Formatters 以了解有关这些内容的更多信息。

    【讨论】:

      【解决方案2】:

      我想补充一点,接受的解决方案对我不起作用。 (.NET Core 3.1)关于 CSP 报告,我有完全相同的用例。当尝试使用 NewtonSoft 并修改 InputFormatter NewtonsoftJsonInputFormatter 以接受媒体标头类型 application/csp-report 时,我总是会收到一个异常,说找不到 inputformatter(有或没有 .AddNewtonsoftJson();

      我通过以下方式设法解决了这个问题:

      services.AddControllers().AddNewtonsoftJson();
      services.AddOptions<MvcOptions>()
            .PostConfigure<IOptions<JsonOptions>, IOptions<MvcNewtonsoftJsonOptions>, ArrayPool<char>, ObjectPoolProvider, ILoggerFactory>(
                (mvcOptions, jsonOpts, newtonJsonOpts, charPool, objectPoolProvider, loggerFactory) =>
                {
                    var formatter = mvcOptions.InputFormatters.OfType<NewtonsoftJsonInputFormatter>().First(i => i.SupportedMediaTypes.Contains("application/json"));
                    formatter.SupportedMediaTypes.Add(MediaTypeHeaderValue.Parse("application/csp-report"));
                    mvcOptions.InputFormatters.RemoveType<NewtonsoftJsonInputFormatter>();
                    mvcOptions.InputFormatters.Add(formatter);
                });
      

      我的模型和控制器操作与问题中发布的相同。

      (我的解决方案来自How to configure two JSON serializers and select the correct one based on the route

      【讨论】:

      • 这对我有用,我使用了JsonInputFormatter而不是NewtonsoftJsonInputFormatter
      • 接受的答案不起作用,但这对我有用
      【解决方案3】:

      上周我遇到了同样的问题,并使用我自己的custom formatter找到了替代解决方案:

      using CspReportLogger.Models;
      using Microsoft.AspNetCore.Mvc.Formatters;
      using Microsoft.Net.Http.Headers;
      using System;
      using System.Text;
      using System.Text.Json;
      using System.Threading.Tasks;
      
      namespace CspReportLogger.Formatters
      {
        public class CSPReportInputFormatter : TextInputFormatter
        {
          public CSPReportInputFormatter()
          {
            // Specify the custom media type.
            SupportedMediaTypes.Add(MediaTypeHeaderValue.Parse("application/csp-report"));
            SupportedEncodings.Add(Encoding.UTF8);
          }
      
          public override async Task<InputFormatterResult> ReadRequestBodyAsync(InputFormatterContext context, Encoding effectiveEncoding)
          {
            // Let ASP interrupt deserialization
            var cancellationToken = context.HttpContext.RequestAborted;
      
            // Avoid InvalidCastException, pull type from controller
            var modelType = context.ModelType;
      
            // Deserialize the body using our models and the JsonSerializer.
            var report = await JsonSerializer.DeserializeAsync(context.HttpContext.Request.Body, modelType, null, cancellationToken);
            return await InputFormatterResult.SuccessAsync(report);
          }
        }
      }
      

      当然必须在 Startup.cs 中注册:

          public void ConfigureServices(IServiceCollection services)
          {
            services.AddControllers(options =>
            {
              options.InputFormatters.Insert(0, new CSPReportInputFormatter());
            });
          }
      

      我希望我早点看到Kirk Larkin's solution,因为它显然更简洁。

      如果您想接受不是有效 json 的正文类型,我认为自定义格式化程序解决方案很有帮助。

      【讨论】:

      • btw asp core 3.1,这个创建自定义文本输入格式化程序的答案是唯一对我有用的东西
      【解决方案4】:

      感谢 rm-code。我确实必须进行一些更改,因为我在以下位置获得了一个空值:

      var report = await JsonSerializer.DeserializeAsync(context.HttpContext.Request.Body, modelType, null, cancellationToken);
      

      这是最终对我有用的方法。

      using Namespace.WebUI.Models;
      using Microsoft.AspNetCore.Mvc.Formatters;
      using Microsoft.Net.Http.Headers;
      using Newtonsoft.Json;
      using System.IO;
      using System.Text;
      using System.Threading.Tasks;
      
      public class CSPReportInputFormatter : TextInputFormatter
      {
          public CSPReportInputFormatter()
          {
              // Specify the custom media type.
              SupportedMediaTypes.Add(MediaTypeHeaderValue.Parse("application/csp-report"));
              SupportedEncodings.Add(Encoding.UTF8);
          }
      
          public override async Task<InputFormatterResult> ReadRequestBodyAsync(InputFormatterContext context, Encoding effectiveEncoding)
          {
              using var reader = new StreamReader(context.HttpContext.Request.Body);
              string responseString = await reader.ReadToEndAsync();
      
              var data = JsonConvert.DeserializeObject<CspReportRequest>(responseString);
      
              return await InputFormatterResult.SuccessAsync(data);
          }
      }
      

      【讨论】:

        猜你喜欢
        • 2020-02-18
        • 2017-08-05
        • 2017-11-16
        • 2016-02-02
        • 1970-01-01
        • 2021-07-16
        • 1970-01-01
        • 2016-06-10
        • 2021-05-14
        相关资源
        最近更新 更多