Необъяснимый 401 ответ от метода PUT на .Net Core 3.1

#c# #rest #asp.net-core #jwt #flurl

#c# #asp.net-ядро #.net-core #jwt #flurl

Вопрос:

У меня есть очень интригующая проблема. У меня есть веб-API .Net Core 3.1 Rest. Справочная информация:

  1. Я правильно настроил аутентификацию в соответствии с другими нашими микросервисами.
  2. Сообщение проходит проверку подлинности правильно и возвращает 200 OK
  3. Операция PUT возвращает 401 несанкционированный
  4. Я ничего не делаю с точки зрения аутентификации по каждому маршруту

Фрагмент контроллера:

 [Route("flights")]
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
public class FlightsController : BaseController
{
    private readonly ILogger<FlightsController> _logger;
    private readonly IStringLocalizer _stringLocalizer;
    private readonly IWebHostEnvironment _environment;
    public FlightsController(ILogger<FlightsController> logger, 
                             IStringLocalizer stringLocalizer, 
                             IWebHostEnvironment environment)
    {
        _logger = logger;     
        _stringLocalizer = stringLocalizer;
        _environment = environment;
    }

    [HttpPost("OrderFlight")]
    public async Task<IActionResult> OrderFlight([FromBody] OrderFlightBindingModel model)
    {
        return Ok(model);
    }

    [HttpPut("OrderFlight")]
    public async Task<IActionResult> ValidateOtp([FromBody] CompleteOrderBindingModel model)
    {
        return Ok(model);
    }
}
 

Фрагмент конфигурации служб запуска:

 //Configure Services
services.AddAuthentication(options =>
{
    options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
    options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(options =>
{
    options.Authority = _config["JWT:Authority"];
    options.Audience = _config["JWT:Audience"];
    options.TokenValidationParameters = new TokenValidationParameters
    {
        ValidateIssuerSigningKey = true,
        ValidateIssuer = true,
        ValidateLifetime = true,
        ValidateAudience = true
    };
});
services.AddAuthorization();
 

фрагмент настройки при запуске:

 //Configure
app.UseAuthentication();
app.UseAuthorization();
 

Любые идеи приветствуются. Я довольно хорошо знаком с .Net Core API, поэтому предположим, что я правильно выполнил соответствующие настройки приложений и что я ничего не пропустил, потому что всего 12 или около того конечных точек, и только одна операция PUT возвращает 401, даже если auth применяется ко всему контроллеру, а не к каждому-основа метода. Я отлаживаю на локальном хостинге, используя VS Professional и Kestrel.

Ответ №1:

Вам не нужно использовать Put, поскольку некоторые браузеры его не поддерживают. Исправьте заголовки действий:

    [Route("OrderFlight")]
    public async Task<IActionResult> OrderFlight([FromBody] OrderFlightBindingModel model)
    {
        return Ok(model);
    }

    [Route("ValidateOtp")]
    public async Task<IActionResult> ValidateOtp([FromBody] CompleteOrderBindingModel model)
    {
        return Ok(model);
    }
and use OrderFlight or ValidateOtp in your url.
 

Комментарии:

1. Это правильное предложение. Однако он даже не работает с мобильных устройств или из интеграционного теста, выполняемого в приложении .Net Console. Работает только post.

2. Для чего вам нужен Post? Поверьте мне. Я никогда не использую методы явно. Позвольте браузеру выбрать метод. Браузер обычно умнее разработчика. Например, браузер обычно выбирает GET для удаления, поскольку действие обычно выглядит так… удалить (идентификатор int). Если вы добавите атрибут удаления, в некоторых случаях у вас тоже возникнут проблемы

3. @CaptainKenpachi — Но если вам нравится читать учебники и создавать модульные тесты, попробуйте [HttpPut(«ValidateOtp»)] . Это может работать для модульных тестов.

Ответ №2:

Ну, я все еще не могу объяснить это поведение, но, по крайней мере, я узнал одну или две вещи:

отправка запроса PUT через FlurlHttp возвращает 401. Отправка точно такого же запроса через PostMan работает, как и ожидалось. Я трижды проверил, и все заголовки, URL, метод и тело идентичны. Так что

Итак, это ошибка, которую мне придется обсудить с разработчиками Flurl. Поскольку запрос PUT работает с PostMan, я уверен, что он также будет работать так же, как и любой другой запрос PUT OTP, который использует те же настройки и работает в наших UAT и производственных средах. Поэтому я создам конечную точку POST с явной целью ее тестирования (что технически плохо, но, в конце концов, я больше забочусь о работающем программном обеспечении, чем о принципах DRY).