You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.24 06:17:05