如何使用 Angular 在 ASP.NET 核心应用程序中正确实施 Windows 身份验证

How to properly implement Windows Authentication in an ASP.NET Core app with Angular

我刚刚按照 this 教程中所述,使用 Angular 创建了一个 ASP.NET 核心应用程序。 创建 ASP.NET 核心项目时,我选中了启用 Windows 身份验证的选项。只要我在 ASP.NET 核心项目中将 [AllowAnonymous] 添加到我的控制器,一切都已经正常工作,但是一旦我将其替换为 [Authorize],来自我 [=60] 的请求=] 应用程序不再在后端访问我的代码。相反,网络服务器 returns 出现 400 Bad Request 错误。这是一个请求,其中包含出现此问题的响应 headers:

在我自己做了一些研究之后,我发现我可能需要在后端启用 CORS,因为我在开发期间在 Angular 应用程序中通过 proxy.conf.json 使用代理。这是proxy.conf.json的内容:

{
  "/api/*": {
    "target": "https://localhost:7139",
    "secure": false,
    "changeOrigin": true
  }
}

因此,我尝试在 ASP.NET 核心项目的 Program.cs 中添加 UseCors()。这是 Program.cs 当前的样子:

using Microsoft.AspNetCore.Authentication.Negotiate;

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.

builder.Services.AddCors(setup =>
{
    setup.AddDefaultPolicy(builder =>
    {
        builder.WithOrigins("http://localhost:4200")
          .AllowAnyHeader()
          .AllowAnyMethod()
          .AllowCredentials();
    });
});

builder.Services.AddAuthentication(NegotiateDefaults.AuthenticationScheme)
   .AddNegotiate();

builder.Services.AddAuthorization(options =>
{
    // By default, all incoming requests will be authorized according to the default policy.
    options.FallbackPolicy = options.DefaultPolicy;
});

builder.Services.AddControllers();

var app = builder.Build();

// Configure the HTTP request pipeline.

app.UseHttpsRedirection();

app.UseCors();

app.UseAuthentication();
app.UseAuthorization();

app.MapControllers();

app.Run();

不幸的是,这似乎没有任何区别。这就是我的 http GET 调用在前端的实现方式:

this.http.get<string>(`api/test/1`, { responseType: 'text', withCredentials: true } as Record<string, unknown>).subscribe(value => {
      alert(value);
    }, error => console.error(error));

我觉得我遗漏了一些重要的东西,我需要让 Windows 身份验证在这里工作,但我不知道我到底做错了什么。我什至没有从网络服务器那里得到任何关于为什么它甚至 returns 400 Bad Request 在这里的额外信息,所以我不知道从哪里开始调试这个问题。

更新:我想出了如何通过在 appsettings.Development.jsonLogging 部分添加以下 configuration-entries 来启用更多 Kestrel-Logging:

"Default": "Debug",
"Microsoft.AspNetCore": "Debug",
"Microsoft.AspNetCore.Server.Kestrel": "Debug",
"Microsoft.AspNetCore.Server.Kestrel.BadRequests": "Debug",
"Microsoft.AspNetCore.Server.Kestrel.Connections": "Debug",
"Microsoft.AspNetCore.Server.Kestrel.Http2": "Debug",
"Microsoft.AspNetCore.Server.Kestrel.Http3": "Debug"

这是 Kestrel 在处理以 400 Bad Request 错误结尾的请求时记录的内容:

dbug: Microsoft.AspNetCore.Server.Kestrel.Connections[39]
      Connection id "0HMGSHHNJQ68N" accepted.
dbug: Microsoft.AspNetCore.Server.Kestrel.Connections[1]
      Connection id "0HMGSHHNJQ68N" started.
dbug: Microsoft.AspNetCore.Server.Kestrel.Https.Internal.HttpsConnectionMiddleware[3]
      Connection 0HMGSHHNJQ68N established using the following protocol: Tls12
info: Microsoft.AspNetCore.Hosting.Diagnostics[1]
      Request starting HTTP/1.1 GET https://localhost:7139/api/test/1 - -
dbug: Microsoft.AspNetCore.HostFiltering.HostFilteringMiddleware[0]
      Wildcard detected, all requests with hosts will be allowed.
dbug: Microsoft.AspNetCore.Routing.Matching.DfaMatcher[1001]
      1 candidate(s) found for the request path '/api/test/1'
dbug: Microsoft.AspNetCore.Routing.Matching.DfaMatcher[1005]
      Endpoint 'WebApp.Controllers.TestController.Get (WebApp)' with route pattern 'api/Test/{id}' is valid for the request path '/api/test/1'
dbug: Microsoft.AspNetCore.Routing.EndpointRoutingMiddleware[1]
      Request matched endpoint 'WebApp.Controllers.TestController.Get (WebApp)'
dbug: Microsoft.AspNetCore.Authentication.Negotiate.NegotiateHandler[9]
      AuthenticationScheme: Negotiate was not authenticated.
info: Microsoft.AspNetCore.Authorization.DefaultAuthorizationService[2]
      Authorization failed. These requirements were not met:
      DenyAnonymousAuthorizationRequirement: Requires an authenticated user.
dbug: Microsoft.AspNetCore.Authentication.Negotiate.NegotiateHandler[6]
      Challenged 401 Negotiate.
info: Microsoft.AspNetCore.Authentication.Negotiate.NegotiateHandler[12]
      AuthenticationScheme: Negotiate was challenged.
dbug: Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets[6]
      Connection id "0HMGSHHNJQ68N" received FIN.
info: Microsoft.AspNetCore.Hosting.Diagnostics[2]
      Request finished HTTP/1.1 GET https://localhost:7139/api/test/1 - - - 401 0 - 189.6680ms
dbug: Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets[7]
      Connection id "0HMGSHHNJQ68N" sending FIN because: "The client closed the connection."
dbug: Microsoft.AspNetCore.Server.Kestrel.Connections[10]
      Connection id "0HMGSHHNJQ68N" disconnecting.
dbug: Microsoft.AspNetCore.Server.Kestrel.Connections[2]
      Connection id "0HMGSHHNJQ68N" stopped.
dbug: Microsoft.AspNetCore.Server.Kestrel.Connections[39]
      Connection id "0HMGSHHNJQ68O" accepted.
dbug: Microsoft.AspNetCore.Server.Kestrel.Connections[1]
      Connection id "0HMGSHHNJQ68O" started.
dbug: Microsoft.AspNetCore.Server.Kestrel.Https.Internal.HttpsConnectionMiddleware[3]
      Connection 0HMGSHHNJQ68O established using the following protocol: Tls12
info: Microsoft.AspNetCore.Hosting.Diagnostics[1]
      Request starting HTTP/1.1 GET https://localhost:7139/api/test/1 - -
dbug: Microsoft.AspNetCore.Routing.Matching.DfaMatcher[1001]
      1 candidate(s) found for the request path '/api/test/1'
dbug: Microsoft.AspNetCore.Routing.Matching.DfaMatcher[1005]
      Endpoint 'WebApp.Controllers.TestController.Get (WebApp)' with route pattern 'api/Test/{id}' is valid for the request path '/api/test/1'
dbug: Microsoft.AspNetCore.Routing.EndpointRoutingMiddleware[1]
      Request matched endpoint 'WebApp.Controllers.TestController.Get (WebApp)'
info: Microsoft.AspNetCore.Authentication.Negotiate.NegotiateHandler[1]
      Incomplete Negotiate handshake, sending an additional 401 Negotiate challenge.
info: Microsoft.AspNetCore.Hosting.Diagnostics[2]
      Request finished HTTP/1.1 GET https://localhost:7139/api/test/1 - - - 401 0 - 68.9309ms
dbug: Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets[6]
      Connection id "0HMGSHHNJQ68O" received FIN.
dbug: Microsoft.AspNetCore.Server.Kestrel.Connections[10]
      Connection id "0HMGSHHNJQ68O" disconnecting.
dbug: Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets[7]
      Connection id "0HMGSHHNJQ68O" sending FIN because: "The client closed the connection."
dbug: Microsoft.AspNetCore.Server.Kestrel.Connections[39]
      Connection id "0HMGSHHNJQ68P" accepted.
dbug: Microsoft.AspNetCore.Server.Kestrel.Connections[1]
      Connection id "0HMGSHHNJQ68P" started.
dbug: Microsoft.AspNetCore.Server.Kestrel.Connections[2]
      Connection id "0HMGSHHNJQ68O" stopped.
dbug: Microsoft.AspNetCore.Server.Kestrel.Https.Internal.HttpsConnectionMiddleware[3]
      Connection 0HMGSHHNJQ68P established using the following protocol: Tls12
info: Microsoft.AspNetCore.Hosting.Diagnostics[1]
      Request starting HTTP/1.1 GET https://localhost:7139/api/test/1 - -
dbug: Microsoft.AspNetCore.Routing.Matching.DfaMatcher[1001]
      1 candidate(s) found for the request path '/api/test/1'
dbug: Microsoft.AspNetCore.Routing.Matching.DfaMatcher[1005]
      Endpoint 'WebApp.Controllers.TestController.Get (WebApp)' with route pattern 'api/Test/{id}' is valid for the request path '/api/test/1'
dbug: Microsoft.AspNetCore.Routing.EndpointRoutingMiddleware[1]
      Request matched endpoint 'WebApp.Controllers.TestController.Get (WebApp)'
dbug: Microsoft.AspNetCore.Authentication.Negotiate.NegotiateHandler[11]
      Negotiate error code: ClientError.
dbug: Microsoft.AspNetCore.Authentication.Negotiate.NegotiateHandler[10]
      The users authentication request was invalid.
      System.ComponentModel.Win32Exception (0x80090308): Das Token, das der Funktion übergeben wurde, ist ungültig.
info: Microsoft.AspNetCore.Hosting.Diagnostics[2]
      Request finished HTTP/1.1 GET https://localhost:7139/api/test/1 - - - 400 0 - 40.9717ms
dbug: Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets[6]
      Connection id "0HMGSHHNJQ68P" received FIN.
dbug: Microsoft.AspNetCore.Server.Kestrel.Connections[10]
      Connection id "0HMGSHHNJQ68P" disconnecting.
dbug: Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets[7]
      Connection id "0HMGSHHNJQ68P" sending FIN because: "The client closed the connection."
dbug: Microsoft.AspNetCore.Server.Kestrel.Connections[2]
      Connection id "0HMGSHHNJQ68P" stopped.

第一个连接 (0HMGSHHNJQ68N) 似乎是我最初在浏览器中输入我的 AD 凭据时获得 login-dialog 的地方。当我输入我的凭据后点击确定时,其他连接就会被记录下来。遗憾的是,我真的无法根据这些日志找出解决问题的方法,但我很确定 Angular 应用程序未正确提供凭据。

我做错了什么and/or我怎样才能找出问题的根本原因?

在您的 CORS 配置中,您尝试以非常广泛的方式打开 API。不幸的是,在处理包含 AUTHORIZATION header 的请求时,您不能使用“*”来允许所有主机,但您需要指定主机。此外,您需要调用 AllowCredentials 来接受带有凭据的请求:

services.AddCors(setup =>
{
  setup.AddDefaultPolicy(builder =>
  {
    builder.WithOrigins("http://localhost:4200")
      .AllowAnyHeader()
      .AllowAnyMethod()
      .AllowCredentials();
  });
});

通常,API 与生产中的 SPA 同源托管,因此在开发环境以外的环境中可以省略这些设置。此外,您可能希望添加配置设置而不是 hard-coding http://localhost:4200.