I just finished creating an ASP.NET Core app with Angular as described in this tutorial.
When creating the ASP.NET Core project, I checked the option to enable Windows Authentication. As long as I add [AllowAnonymous]
to my controllers in the ASP.NET Core project, everything already works just fine, but as soon as I replace that with [Authorize]
, the requests from my Angular app no longer reach my code in the backend. Instead, the webserver returns a 400 Bad Request
error. Here is a request including the response headers where this problem occurs:
After doing some research on my own, I found out that I probably need to enable CORS in the backend, since I am using a proxy via proxy.conf.json
in the Angular app during development. Here is the content of the proxy.conf.json
:
{
"/api/*": {
"target": "https://localhost:7139",
"secure": false,
"changeOrigin": true
}
}
Therefore, I tried to add UseCors()
in my Program.cs
of the ASP.NET Core project. Here is how the Program.cs
currently looks like:
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();
Unfortunately, this does not seem to make any difference. This is how my http GET call is implemented in the frontend:
this.http.get<string>(`api/test/1`, { responseType: 'text', withCredentials: true } as Record<string, unknown>).subscribe(value => {
alert(value);
}, error => console.error(error));
I feel like I am missing something important which I need to make Windows Authentication work here, but I don't know what exactly I am doing wrong. I do not even get any additional information from the webserver about why it even returns 400 Bad Request
here, so I don't know where to start debugging this issue.
UPDATE: I figured out how to enable more Kestrel-Logging by adding the following configuration-entries in the Logging
section of my appsettings.Development.json
:
"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"
Here is what Kestrel is logging while handling the request which ends with a 400 Bad Request
error:
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.
The first connection (0HMGSHHNJQ68N ) seems to be where I initially get the login-dialog in my browser where I enter my AD credentials. The other connections are then logged when I hit OK after entering my credentials. Sadly, I can't really figure out how to solve the problem based on those logs, but I am quite sure that the credentials are not provided correctly from the Angular app.
What am I doing wrong and/or how can I figure out the root cause of the problem?
https://localhost:7139/api/test/1
, enter my AD credentials and it works just fine. Therefore, I think that the Angular app does not yet know how to deal with the credentials, but I have no clue how to configure it to do that. I also figured out how to get more useful logging out of Kestrel. I added the logs and the content of myproxy.conf.json
to my question above. Do you have an idea how I can make this work? – Grandiosethis.http.get<string>('https://localhost:7139/api/test/1', ...
? – ChoosyAccess to XMLHttpRequest at 'https://localhost:7139/api/test/1' from origin 'https://localhost:4200' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
– Grandiosebuilder.WithOrigins("https://localhost:4200")
instead ofbuilder.WithOrigins("http://localhost:4200")
– Galantine