【问题标题】:When I make a POST to my Web API I get a 401 exception当我对我的 Web API 进行 POST 时,我得到一个 401 异常
【发布时间】:2026-02-03 22:35:01
【问题描述】:

我正在我的开发机器上使用 localhost 对 Web Core API 服务器进行 Ajax 调用。 这是进行调用的代码;

addDataToDatabase = function (callback, errorCallback, url, data) {
    $.ajax({
        async: true,
        url: url,
        contentType: "application/json",
        dataType: "text",
        data: data,
        type: "POST",
        xhrFields: { withCredentials: true }
    })
        .done(function (data) {
            callback(data);
        })
        .fail(function (data) {
            errorCallback(data);
        });

但是,我收到了 401 未经授权的用户异常。 在我的启动配置方法中,我将 CORS 设置如下

    var url = Configuration["originUrl"];
    app.UseCors(
        options => options.WithOrigins(url).AllowAnyHeader().AllowAnyMethod().AllowCredentials()
    ); 

在我的 appSettings 文件中,我设置了 orginUrl:

"originUrl": "http://localhost:12345"

这一切都适用于 GET 类型的调用,但不适用于 POST。 我需要解决什么问题?

编辑 - 根据要求,这是完整的启动代码;

using Microsoft.AspNetCore.Mvc.ApplicationParts;

namespace Properties.API
{
    using Domain;
    using Domain.Interfaces;
    using Domain.Repo;
    using EF6;
    using Helper;
    using Microsoft.AspNetCore.Builder;
    using Microsoft.AspNetCore.Hosting;
    using Microsoft.Extensions.Configuration;
    using Microsoft.Extensions.DependencyInjection;
    using Microsoft.Extensions.Logging;
    using NLog;
    using NLog.Config;
    using NLog.Extensions.Logging;
    using NLog.Web;
    using Sir.EF6;
    using Sir.EF6.Interfaces;
    using Sir.EF6.Repo;

    public class Startup
    {
        public Startup(IHostingEnvironment env)
        {
            var builder = new ConfigurationBuilder()
                .SetBasePath(env.ContentRootPath)
                .AddJsonFile("appSettings.json", optional: false, reloadOnChange: true)
                .AddJsonFile($"appSettings.{env.EnvironmentName}.json", optional: true, reloadOnChange: true)
                .AddEnvironmentVariables();

            Configuration = builder.Build();
        }

        public static IConfigurationRoot Configuration;

        // This method gets called by the runtime. Use this method to add services to the container.
        // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
        public void ConfigureServices(IServiceCollection services)
        {
            var manager = new ApplicationPartManager();
            manager.ApplicationParts.Add(new AssemblyPart(typeof(Startup).Assembly));
            services.AddSingleton(manager);
            services.AddCors();
            services.AddMvcCore().AddJsonFormatters();
            services.Configure<IISOptions>(options => new IISOptions
            {
                AutomaticAuthentication = true,
                ForwardClientCertificate = false,
                ForwardWindowsAuthentication = false
            });

            var connectionStringMSurveyV2 = Configuration.GetConnectionString("MSurveyV2Db");
            services.AddScoped<MSurveyV2Db>(_ => new MSurveyV2Db(connectionStringMSurveyV2));
            var connectionStringSir = Configuration.GetConnectionString("SirDb");
            services.AddScoped<SirDb>(_ => new SirDb(connectionStringSir));
            services.AddScoped<IPropertiesRepo, PropertiesRepo>();
            services.AddScoped<ISirUoW, SirUoW>();
            services.AddScoped<IPropertyUoW, PropertyUoW>();
            services.AddScoped<Services.IMailService, Services.MailService>();
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
        {
            loggerFactory.AddConsole();
            loggerFactory.AddDebug();
            loggerFactory.AddNLog();
            LogManager.Configuration = new XmlLoggingConfiguration(@"nlog.config");
            var connectionString = Configuration.GetConnectionString("SirNLogDb");
            LogManager.Configuration.Variables["SirNLogDb"] = connectionString;
            app.AddNLogWeb();

            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            else
            {
                app.UseExceptionHandler();
            }

            var url = Configuration["originUrl"];
            app.UseCors(
                options => options.WithOrigins(url).AllowAnyHeader().AllowAnyMethod().AllowCredentials()
            );

            app.UseMvc();
            AutomapperInit.Set();
            var logger = LogManager.GetCurrentClassLogger();
            logger.Info("Started Properties Web API");
            logger.Info($"Origin url = {url}");
        }
    }
}

这是一个引发401异常的POST方法;

[HttpPost("add")]
public async Task<IActionResult> Add([FromBody] InspectionVisitInputDto inspectionVisitDto)
{
    this.NLogger.Info("api/inspectionVisit/add".ToPrefix());
    if (inspectionVisitDto == null)
    {
        NLogger.Error("No data sent");
        return BadRequest(ModelState);
    }

    if (inspectionVisitDto.InspectionId < 1)
    {
        NLogger.Error($"Invalid InspectionId < 1 (actual value is {inspectionVisitDto.InspectionId}");
        return BadRequest(ModelState);
    }

    var inspectionVisit = Mapper.Map<InspectionVisit>(inspectionVisitDto);
    var dateOfVisit = inspectionVisit.DateOfVisit.Date;
    try
    {
        var existingInspectionVisit = this.SirUoW.InspectionVisit.GetItem(
            x => x.InspectionId == inspectionVisit.InspectionId &&
                 DbFunctions.TruncateTime(x.DateOfVisit) == dateOfVisit &&
                 x.ContractSubcontractorId == inspectionVisit.ContractSubcontractorId &&
                 x.SelectedInspectorUsername == inspectionVisit.SelectedInspectorUsername &&
                 x.WorkPhaseId == inspectionVisit.WorkPhaseId);
        if (existingInspectionVisit?.InspectionVisitId > 0)
        {
            NLogger.Info($"Inspection Visit Id = {existingInspectionVisit.InspectionVisitId} already exists.");
            return Ok(existingInspectionVisit.InspectionVisitId);
        }
    }
    catch (Exception e)
    {
        var message = "Cannot get inspection visit";
        await ReportException(e, message);
        var status = OperationStatus.CreateFromException(message, e);
        return BadRequest(status);
    }

    NLogger.Info("Add New Inspection Visit");
    try
    {
        this.SirUoW.InspectionVisit.Add(inspectionVisit);
        await SirUoW.LoggedInSaveChangesAsync(this.LoggedInUser);
        NLogger.Info("New Inspection Visit Saved, id = " + inspectionVisit.InspectionVisitId);

        if (inspectionVisit.ContractSubcontractorId != null)
        {
            await SaveContractSubcontractorIdForInspection(inspectionVisitDto);
        }

        return Ok(inspectionVisit.InspectionVisitId);
    }
    catch (Exception e)
    {
        var message = "Cannot save " + inspectionVisitDto;
        await ReportException(e, message);
        var status = OperationStatus.CreateFromException(message, e);
        return BadRequest(status);
    }
}

这是一个可以正常工作的 GET 方法

[HttpGet("getall")]
public async Task<IActionResult> GetContracts()
{
    this.NLogger.Info("api/contracts/getall".ToPrefix());
    try
    {
        var contracts = this.SirUoW.ViewAllContracts.GetList(x => x.IsMainDivision && x.EndDate == null).OrderBy(x => x.FullContractNo).ToList();
        return Ok(contracts);
    }
    catch (Exception e)
    {
        var message = "Error getting contracts";
        await ReportException(e, message);
        var status = OperationStatus.CreateFromException(message, e);
        return BadRequest(status);
    }
}

【问题讨论】:

  • 这不是 CORS 的问题。这是在请求中对用户进行身份验证的问题。
  • 那我该如何解决呢?部署应用没有问题,运行 Fiddler 也没有问题。
  • 与我们分享完整的Startup.cs 以及 GetPost 方法代码。
  • @Tao Zhou - 完成

标签: ajax asp.net-core-webapi


【解决方案1】:

您的方案是结合 IIS Windows AuthenticaitonCORS,因为 preflight request OPTIONS 不包含任何安全标头,它会遇到错误401

尝试以下解决方法:

  1. appsettings.json 中启用anonymousAuthentication

    {
      "iisSettings": {
      "windowsAuthentication": true,
     "anonymousAuthentication": true
     }
    }
    
  2. 要启用身份验证,请尝试Filter 禁用匿名访问。

      services.AddMvc(config =>
        {
            var policy = new AuthorizationPolicyBuilder()
                .RequireAuthenticatedUser()
                .Build();
            config.Filters.Add(new AuthorizeFilter(policy));
        });   
    

【讨论】:

  • 这给我一个“响应状态代码不表示成功:500(内部服务器错误)。”获取请求
  • @arame3333 如果在GetPost 方法上设置断点,它们会被命中吗?详细的错误信息是什么?
最近更新 更多