415 Неподдерживаемый тип носителя для приложения Content-Type / csp-report в ASP.NET Core

У меня есть политика безопасности контента, которая заставляет 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; }
}

person Brian    schedule 19.01.2020    source источник


Ответы (4)


В следующем примере показано, как добавить поддержку SystemTextJsonInputFormatter для обработки дополнительных типов мультимедиа:

services.AddControllers(options =>
{
    var jsonInputFormatter = options.InputFormatters
        .OfType<SystemTextJsonInputFormatter>()
        .Single();

    jsonInputFormatter.SupportedMediaTypes.Add("application/csp-report");
});

Это двухэтапный процесс:

  1. Просмотрите настроенный список устройств форматирования ввода, чтобы найти SystemTextJsonInputFormatter.
  2. Добавьте application/csp-report к существующему списку поддерживаемых типов носителей (application/json, text/json и application/*+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. В коллекции есть два экземпляра этого типа, поэтому мы нацелены на первый (см. этот ответ для уточнения деталей).

См. Форматирующие устройства ввода в документации по ASP.NET Core, чтобы узнать о них больше.

person Kirk Larkin    schedule 19.01.2020

Хочу добавить, что принятое решение у меня не сработало. (.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);
          });

Моя модель и действие контроллера такие же, как и в вопросе.

(Я получил свое решение из Как настроить два сериализатора JSON и выбрать правильный на основе маршрута)

person Vincent Rutten    schedule 02.03.2020
comment
Это сработало для меня с небольшой корректировкой, которую я использовал JsonInputFormatter вместо NewtonsoftJsonInputFormatter - person Crhistian Ramirez; 16.04.2020
comment
Принятый ответ не сработал, но у меня это сработало - person LP13; 04.05.2021

На прошлой неделе у меня была такая же проблема, и я нашел альтернативное решение, используя свой собственный пользовательский модуль форматирования:

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());
      });
    }

Хотел бы я раньше видеть решение Кирка Ларкина, поскольку оно, очевидно, более лаконично.

Я полагаю, что решение для настраиваемого форматирования полезно, если вы хотите принимать типы тела, которые не являются допустимыми json.

person rm-code    schedule 23.01.2020
comment
btw asp core 3.1, этот ответ о создании настраиваемого средства форматирования текстового ввода - единственное, что сработало для меня - person djeikyb; 20.10.2020

Спасибо 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);
    }
}
person Energy CJ    schedule 04.03.2021