ASP.NET Core 2.0 HttpSys Аутентификация Windows не выполняется с помощью атрибута Authorize (InvalidOperationException: не указана идентификационная схема)

Я пытаюсь перенести приложение ASP.NET Core 1.1 в ASP.NET Core 2.0.

Приложение довольно простое и включает в себя следующее:

  • Хостинг на HttpSys (ранее WebListener)
  • Использование проверки подлинности Windows: options.Authentication.Schemes = AuthenticationSchemes.NTLM
  • Разрешение анонимной аутентификации: options.Authentication.AllowAnonymous = true (потому что есть некоторые контроллеры, для которых не требуется аутентификация)
  • Контроллеры, требующие аутентификации, украшены атрибутом [Authorize].

Проект компилируется и запускается просто отлично. Он также обслуживает действия контроллеров, которые не требуют аутентификации.

Однако, как только я нахожу контроллер с атрибутом [Authorize], я получаю следующее исключение:

System.InvalidOperationException: No authenticationScheme was specified,
and there was no DefaultChallengeScheme found.
   at Microsoft.AspNetCore.Authentication.AuthenticationService.<ChallengeAsync>d__11.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Microsoft.AspNetCore.Mvc.ChallengeResult.<ExecuteResultAsync>d__14.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.<InvokeResultAsync>d__19.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.<InvokeFilterPipelineAsync>d__17.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.<InvokeAsync>d__15.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Microsoft.AspNetCore.Builder.RouterMiddleware.<Invoke>d__4.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.<Invoke>d__7.MoveNext()

Я начал возиться с шаблонами проектов и заметил, что я мог бы легко воспроизвести это с помощью стандартного шаблона ASP.NET Core Web Application (Model-View-Controller) с проверкой подлинности Windows.

Файл Program.cs был изменен следующим образом:

    public static IWebHost BuildWebHost(string[] args) =>
        WebHost.CreateDefaultBuilder(args)
            .UseHttpSys(options =>
            {
                options.Authentication.Schemes = AuthenticationSchemes.NTLM;
                options.Authentication.AllowAnonymous = true;
                options.MaxConnections = 100;
                options.MaxRequestBodySize = 30000000;
                options.UrlPrefixes.Add("http://localhost:5000");
            })
            .UseStartup<Startup>()
            .Build();

Это происходит прямо из документации HttpSys. Также я добавил атрибут [Authorize] в класс HomeController. Теперь он будет производить точно такое же исключение, как показано.

Я нашел некоторые связанные записи (здесь, здесь и здесь), но ни одна из них не связана с простой аутентификацией Windows (и ответы, похоже, не обобщаются).

Ответ 1

Во время написания сообщения я вспомнил, что перешел в этот подраздел руководства по миграции. В нем говорится добавить

services.AddAuthentication(Microsoft.AspNetCore.Server.IISIntegration.IISDefaults.AuthenticationScheme);

к функции ConfigureServices.

Первоначально я думал, что это не относится к HttpSys, поскольку полное имя константы (особенно IISIntegration отбросило меня). Кроме того, на момент написания этой статьи HttpSys documentation полностью не упоминается об этом.

Для таргетинга на всю платформу .NET Framework требуется установка пакета Microsoft.AspNetCore.Authentication NuGet.

ИЗМЕНИТЬ

Как указывает Тратчер, есть аналогичная константа из пространства имен HttpSys, которое вы должны использовать:

Microsoft.AspNetCore.Server.HttpSys.HttpSysDefaults.AuthenticationScheme

Ответ 2

Ответ Андреаса дал мне правильный путь, но это то, что сработало для меня:

Добавлена ​​ссылка на пакет Microsoft.AspNetCore.Authentication

а затем для Startup.cs

using Microsoft.AspNetCore.Server.IISIntegration;

public void ConfigureServices(IServiceCollection services)
{
    ...
    services.AddAuthentication(IISDefaults.AuthenticationScheme);
    ...
}

Ответ 3

Другое дело, если вы уже добавили services.AddAuthentication(IISDefaults.AuthenticationScheme); Обязательно включите тип аутентификации (окна, формы) в iis в приложении → аутентификация. Все мои были отключены и получали эту ошибку даже с кодом на месте.