【问题标题】:Windows Authentication for Kestrel hosted in Windows service托管在 Windows 服务中的 Kestrel 的 Windows 身份验证
【发布时间】:2019-05-19 11:00:57
【问题描述】:

我正在运行托管在 Windows 服务中的 ASP.NET Core 应用程序,如下所述:

https://docs.microsoft.com/en-us/aspnet/core/host-and-deploy/windows-service?view=aspnetcore-2.1

我需要这个应用程序来支持 Windows 身份验证。我有哪些选择?我尝试使用 IIS 中的应用程序请求路由/URL 重写模块作为具有 Windows 身份验证的反向代理,但无法弄清楚如何使其工作。任何指导将不胜感激。

【问题讨论】:

  • 快一年了,有没有好的解决办法?
  • 最终使用 http.sys 而不是 Kestrel。对结果感到满意。

标签: .net asp.net-core windows-services kestrel-http-server


【解决方案1】:

.NET Core Web 应用程序可以使用不同的 Web 服务器:

  • IIS Express(在 Visual Studio 中按 F5 时)
    支持 NTLM、协商 (Kerberos)
    仅限 Windows
  • IIS(部署到 IIS 文件夹时)
    支持 NTLM,协商
    仅限 Windows
  • Kestrel(使用“dotnet run”或从命令行执行时)
    支持协商(使用 nuget 包,请参阅 Yush0s 回复)
    视窗/Linux
  • http.sys(与 kestrel 类似,但在 Startup.cs 中配置)
    支持 NTLM,协商
    仅限 Windows

IIS / IIS Express 中的 Windows 身份验证可以正常工作。

Kestrel 只能使用协商 (Kerberos)。这意味着您需要使用服务主体名称 (SPN) 设置受信任的连接。这可以使用 setspn 命令行工具来完成。不幸的是我没有这方面的经验,因为在开发机器上你往往会跳过它。

http.sys 可以使用 NTLM,但与 IIS / IIS Express 不兼容。这意味着您在使用它时不能使用 Visual Studio 调试。作为一种解决方法,您可以添加一个决定是否使用 http.sys 的环境变量。例如,将以下行添加到 launchSettings.json 中的“项目”配置文件:

  "environmentVariables": {
    "ASPNETCORE_ENVIRONMENT": "Development",
    "USE_HTTP_SYS": "true"
  }

现在可以有条件地使用或不使用 http.sys:

 public static IHostBuilder CreateHostBuilder(string[] args) => Host.CreateDefaultBuilder(args).ConfigureWebHostDefaults(webBuilder =>
        {
            if (bool.Parse(Environment.GetEnvironmentVariable("USE_HTTP_SYS") ?? "false"))
            {
                webBuilder.UseHttpSys(options =>
                {
                    options.Authentication.Schemes = AuthenticationSchemes.NTLM;
                    options.Authentication.AllowAnonymous = false;
                });
            }

            webBuilder.UseStartup<Startup>();
        });

作为旁注,从 .NET Core 3.0 开始,有一个新接口“IHostBuilder”而不是“IWebHostBuilder”(仅为向后兼容而存在)。


遗憾的是,当您使用“dotnet run”并转到该网站时,您可能会看到一条错误消息:

  • Internet Explorer:无法安全连接到此页面
  • Chrome:无法访问此站点
  • Firefox:无法连接

Kestrel 带来了它自己的证书管理。它在用户模式下运行并在“CurrentUser\My”中查找证书。相比之下 http.sys 是内核模式,这意味着当前用户是未知的。 http.sys 在“LocalMachine\My”中查找证书。

由于http.sys不知道端口使用的是哪个证书,所以还需要将证书分配给.net应用的https端口。这需要以本地管理员身份通过 PowerShell 完成:

$cert = Get-ChildItem -Path Cert:\LocalMachine\My | Where { $_.Subject -eq "CN=localhost" } | Select -First 1
netsh http add sslcert ipport=0.0.0.0:5001 appid='{12345678-1234-43f8-a778-f05f3c6b9709}' certhash=$($cert.Thumbprint)

请注意,“CN=localhost”是 uri,“0.0.0.0:5001”是 dotnet 应用程序的端口,appid 是随机标识符(如果您的应用程序有 guid,您也可以使用它,但它是不需要)。

如果您没有证书(例如用于开发),您可以为机器创建一个自签名证书(需要 Win10 和管理员权限):

$rootextension = [System.Security.Cryptography.X509Certificates.X509BasicConstraintsExtension]::new($true, $true, 0, $true)
$cert = New-SelfSignedCertificate -Subject "CN=localhost" -FriendlyName "Development localhost Certificate" -Extension $rootextension -NotAfter ([DateTime]::Now).AddYears(10) -KeyUsage DigitalSignature,KeyEncipherment,DataEncipherment -CertStoreLocation "Cert:\LocalMachine\My" -KeyExportPolicy Exportable

【讨论】:

    【解决方案2】:

    使用 .Net Core 3.0,您可以将 Windows 身份验证与 Kestrel 一起使用。它有一个 Nuget 包:Microsoft.AspNetCore.Authentication.Negotiate

    然后您可以在 Startup.ConfigureServices 中添加它:

    services.AddAuthentication(NegotiateDefaults.AuthenticationScheme)
       .AddNegotiate();
    

    更多信息另见:
    https://docs.microsoft.com/en-us/aspnet/core/security/authentication/windowsauth?view=aspnetcore-3.0&tabs=visual-studio#kestrel

    【讨论】:

    • 我已按照您链接上的说明进行操作,但由于某种原因,它不允许 NTLM。只能协商。你有什么想法吗?
    • 您是在 windows 还是 linux 下运行您的应用程序?使用 windows 尝试使用域用户运行服务。
    • Windows 10。我正在使用域用户运行它。
    • 你也有 app.UseAuthentication();?一旦我们可以将我们的 prod 应用程序升级到 .net core 3,我将对其进行进一步测试
    • 我想添加一个名为/login 的路由,该路由将从前端客户端获取用户名和密码......假设来自 [FromBody]。我应该调用哪种方法来使用收到的凭据对用户进行身份验证?
    【解决方案3】:

    微软有一整篇关于Windows Authentication in ASP.NET Core的文章,包括section describing how to do it without IIS。 Kestrel 不支持 Windows 身份验证,因此您必须使用 HTTP.sys 进行托管。一开始看起来很简单(在您的 Program.cs 中):

    .UseHttpSys(options =>
    {
        options.Authentication.Schemes = 
            AuthenticationSchemes.NTLM | AuthenticationSchemes.Negotiate;
        options.Authentication.AllowAnonymous = false;
    })
    

    直到你意识到有一个whole other article about hosting in HTTP.sys,所以你可能会找到一些其他原因,它可能会破坏其他东西。

    host it in IIS(而不是 Windows 服务)和let IIS handle the Windows Authentication 可能更容易。

    您决定首先托管在 Windows 服务中是有原因的吗?

    【讨论】:

    • 谢谢加布里埃尔。在 IIS 中托管适用于无状态请求/响应应用程序。但是,如果您通过 BackgroundService 运行专用线程来执行与请求无关的事情,那么 IIS 不是一个很好的主机。您可以配置 IIS 以防止空闲关机并在重新启动后自动启动,但 Windows 服务是专门为此设计的,而让 IIS 执行此操作是一种黑客行为。然后您可能会问为什么不使用 .NET Framework?好吧,像原生依赖注入等所有很酷的功能都在 .NET Core 中。
    • 有道理:)
    • 如果问题太大,您可以拆分应用程序:将 Windows 服务用于后台进程,将托管在 IIS 中的单独 Web 应用程序用于前端。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多