ASP.NET Core 6 Web API Windows认证用户身份返回Null问题
我正在使用启用Windows认证的ASP.NET Core 6 Web API,需要获取运行应用的「默认用户」并执行后续查询。代码在Swagger(VS 2022)中运行正常,但通过Postman或Angular 15调用时,用户身份返回Null;不过在Postman中选择NTLM认证头并输入账号密码后可正常工作。
相关配置代码
launchSettings.json
{ "profiles": { "PTMWeb": { "commandName": "Project", "launchBrowser": true, "launchUrl": "swagger", "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" }, "dotnetRunMessages": true, "applicationUrl": "http://localhost:5170" }, "IIS Express": { "commandName": "IISExpress", "launchBrowser": true, "launchUrl": "swagger", "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" } } }, "$schema": "https://json.schemastore.org/launchsettings.json", "iisSettings": { "windowsAuthentication": true, "anonymousAuthentication": false, "iisExpress": { "applicationUrl": "http://localhost:5170", "sslPort": 0 } } }
program.cs
using Microsoft.EntityFrameworkCore; using System.Text.Json.Serialization; using System.Text.Json; using Microsoft.AspNetCore.Http.Json; using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Authentication.Negotiate; using Microsoft.Extensions.Options; using Microsoft.AspNetCore.Authentication; var builder = WebApplication.CreateBuilder(args); // Add services to the container builder.Services.AddSingleton<IClaimsTransformation, ClaimsTransformer>(); builder.Services.AddControllers().AddJsonOptions(jsonOptions => { jsonOptions.JsonSerializerOptions.PropertyNamingPolicy = null; }); builder.Services.AddDbContext<PtmDBContext>(options => { options.UseSqlServer(builder.Configuration.GetConnectionString("ptm-connection")); }); builder.Services.AddScoped<IUserRepository, UserRepository>(); builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSwaggerGen(); 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.AddAutoMapper(AppDomain.CurrentDomain.GetAssemblies()); // Set the JSON serializer options builder.Services.Configure<JsonOptions>(options => { options.SerializerOptions.PropertyNameCaseInsensitive = false; options.SerializerOptions.PropertyNamingPolicy = null; options.SerializerOptions.WriteIndented = true; }); var MyAllowSpecificOrigins = ""; builder.Services.AddCors(options => { options.AddPolicy(MyAllowSpecificOrigins, policy => { policy.WithOrigins("http://localhost:4200"); policy.AllowAnyOrigin(); policy.AllowAnyHeader(); policy.AllowAnyMethod(); }); }); builder.Services.AddHttpContextAccessor(); var app = builder.Build(); // Configure the HTTP request pipeline. if (app.Environment.IsDevelopment()) { app.UseSwagger(); app.UseSwaggerUI(); } app.UseCors(builder => { builder.WithOrigins("http://localhost:4200"); }); app.UseRouting(); app.UseCors(MyAllowSpecificOrigins); app.UseAuthentication(); app.UseAuthorization(); app.MapControllers(); app.Run();
Controller代码
[Route("api/[controller]")] [ApiController] public class UserController : ControllerBase { private readonly IUserRepository _userRepository; private readonly IHttpContextAccessor httpC; public UserController(IHttpContextAccessor _httpC, IUserRepository userRepository) { httpC = _httpC; _userRepository = userRepository; } [AllowAnonymous] [HttpGet("GetDefaultUser")] public async Task<ActionResult<ServiceResponse<GetUserDto>>> GetDefaultUser() { string? _name = httpC.HttpContext.User.Identity.Name; if (_name != null) //returns null here { var slashIndex = _name.IndexOf("\\"); var _userId = slashIndex > -1 ? _name.Substring(slashIndex + 1) : _name.Substring(0, _name.IndexOf("@")); var result = await _userRepository.GetUser(_userId); if (result == null) return NotFound(); return Ok(result); } else { return NotFound(); } } }
1. CORS配置未允许凭据传递
Windows认证(NTLM/Kerberos)属于带凭据的跨域请求,现有CORS策略未开启允许凭据,导致浏览器/Postman默认不会发送用户凭据。
修复:
修改CORS配置,添加AllowCredentials(),同时移除冲突的AllowAnyOrigin()(AllowCredentials()与AllowAnyOrigin()无法共存):
var MyAllowSpecificOrigins = "AllowAngularOrigin"; // 给策略命名,避免空字符串 builder.Services.AddCors(options => { options.AddPolicy(MyAllowSpecificOrigins, policy => { policy.WithOrigins("http://localhost:4200") // 指定允许的源 .AllowAnyHeader() .AllowAnyMethod() .AllowCredentials(); // 关键:允许传递凭据 }); });
同时清理program.cs中重复的UseCors调用,保持中间件顺序正确:
// 移除重复的UseCors调用,只保留一个且放在UseRouting之前 app.UseCors(MyAllowSpecificOrigins); app.UseRouting(); // 移除此处的UseCors(MyAllowSpecificOrigins)
2. Kestrel未启用Windows认证
launchSettings.json仅在IIS Express配置了Windows认证,使用Kestrel(PTMWeb配置)启动时未开启认证,导致非IIS环境下身份不生效。
修复:
在PTMWeb配置中添加Windows认证环境变量:
"PTMWeb": { "commandName": "Project", "launchBrowser": true, "launchUrl": "swagger", "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development", "ASPNETCORE_WINDOWS_AUTHENTICATION": "true", // 开启Windows认证 "ASPNETCORE_ANONYMOUS_AUTHENTICATION": "false" // 禁用匿名认证 }, "dotnetRunMessages": true, "applicationUrl": "http://localhost:5170" }
或在program.cs中直接配置Kestrel:
builder.WebHost.ConfigureKestrel(options => { options.ListenAnyIP(5170, listenOptions => { listenOptions.UseWindowsAuthentication(); }); });
3. 控制器方法添加了[AllowAnonymous]
[AllowAnonymous]会跳过认证中间件处理,导致User.Identity始终为Null,既然需要获取用户身份,就不能允许匿名访问。
修复:
移除GetDefaultUser方法上的[AllowAnonymous]属性:
// [AllowAnonymous] 移除此行 [HttpGet("GetDefaultUser")] public async Task<ActionResult<ServiceResponse<GetUserDto>>> GetDefaultUser() { // ... 原有代码 }
4. Angular端需配置携带凭据
Angular发送跨域请求时默认不携带用户凭据,需显式设置withCredentials: true:
示例(Angular HTTP请求):
this.http.get('http://localhost:5170/api/User/GetDefaultUser', { withCredentials: true }) .subscribe(response => { // 处理响应 });
内容的提问来源于stack exchange,提问作者gjo

