如何使用 ASP.NET Core 解决 REACT 中的 CORS 错误

Posted

技术标签:

【中文标题】如何使用 ASP.NET Core 解决 REACT 中的 CORS 错误【英文标题】:How to resolve CORS error in REACT with ASP.NET Core 【发布时间】:2021-11-10 18:45:49 【问题描述】:

我有一个 ASP.NET Core Web API 和一个单独的 React 应用程序。 Web API 使用 Windows 身份验证。部署到服务器时,我没有任何问题,但是当我尝试在本地运行应用程序时,我收到 CORS 错误,并且仅在 POST 操作上。这是我在Startup.cs 中的内容:

using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.OpenApi.Models;
using Server.DAL;
using Server.Data;

namespace Server

    public class Startup
    
        public Startup(IConfiguration configuration)
        
            Configuration = configuration;
        

        public IConfiguration Configuration  get; 

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        
            services.AddDbContext<AppDbContext>(options => options
               .UseSqlServer(Configuration.GetConnectionString("DatabaseConnection"))
               .UseLazyLoadingProxies());

            services.AddScoped<IUnitOfWork, UnitOfWork>();

            services.AddControllers();

            services.AddCors(options => options.AddPolicy("CorsPolicy",
                builder =>
                
                    builder
                    .WithOrigins("http://localhost:3000")                        
                    .AllowAnyMethod()
                    .AllowAnyHeader()
                    .AllowCredentials();
                ));    
        

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        
            if (env.IsDevelopment())
            
                app.UseDeveloperExceptionPage();
            

            app.UseSwagger();

            app.UseHttpsRedirection();

            app.UseRouting();

            app.UseCors("CorsPolicy");

            app.UseAuthorization();

            app.UseEndpoints(endpoints =>
            
                endpoints.MapControllers();
            );
        
    

还有,这是我在 React 应用中的 axios 配置:

import axios,  AxiosInstance  from "axios";

let axiosInstance: AxiosInstance;

const axiosBaseConfig = 
  baseURL: process.env.REACT_APP_BASE_URL,
  timeout: 1000 * 20,
  withCredentials: true,
  headers: 
    Accept: "applicaiton/json",
    "Content-Type": "application/json",
  ,
;

export const getAxios = () => 
  if (axiosInstance) 
    return axiosInstance;
  

  axiosInstance = axios.create(axiosBaseConfig);

  return axiosInstance;
;

我在这里有什么遗漏或做错了吗?

更新:

这是我得到的 CORS 错误:

从源“http://localhost:3000”访问“https://localhost:44376/api/reservation”处的 XMLHttpRequest 已被 CORS 策略阻止:对预检请求的响应未通过访问控制检查:响应中“Access-Control-Allow-Credentials”标头的值为“”,当请求的凭据模式为“包含”时,该值必须为“真”。 XMLHttpRequest 发起的请求的凭证模式由 withCredentials 属性控制。

【问题讨论】:

尝试将 services.AddCors 移到顶部并删除 .AllowCredentials(); @Serge 我需要 AllowCredentials,因为它是 Windows 身份验证。 不用这个就试试吧 您能否将“CORS 错误”添加到您的问题中? 对于本地开发,只需在关闭 CORS 的情况下启动浏览器! alfilatov.com/posts/run-chrome-without-cors 【参考方案1】:

试试这个:-

在你的ConfigureServices

services.AddCors();

还有你的配置方法app.UseCors(x =&gt; x.AllowAnyHeader().AllowAnyMethod().WithOrigins("http://localhost:3000"));

希望它能解决您的问题。

【讨论】:

那行不通。 @ataravati 它会帮助你:- ***.com/questions/57009371/… 当我将 AddCors() 和 app.UseCors(x => x.AllowAnyHeader().AllowAnyMethod().WithOrigins("localhost:3000")); 移到它们的顶部时,它对我有用相应的方法,并确保 localhost:3000 上没有斜杠。 这对我有用【参考方案2】:

您可以尝试如下添加:

public void Configure(IApplicationBuilder app, IWebHostEnvironment env) 
 ...
 app.UseCors(cors => cors.AllowAnyOrigin().AllowAnyHeader().AllowAnyMethod());
 app.UseAuthorization();
 ...


public void ConfigureServices(IServiceCollection services) 
 ...
 services.AddCors(c =>  c.AddPolicy("AllowOrigin", options => options.AllowAnyOrigin()); );
 services.AddControllers();
 ...

【讨论】:

这不是我在做的吗? @ataravati 这是实际生产的代码。如果它仍然不起作用,您应该重新克隆项目并在另一个目录中重建它。您可以逐步检查: - 检查后端:通过 Postman 调用本地 API。 - 检查前端:将前端的 API URL 更改为生产 API 并运行它。希望对你有帮助。 正如我在帖子中提到的,它可以在生产环境中使用。它在开发中不起作用。【参考方案3】:

如果你有一个 create-react-app 项目,解决这个问题的方法是在你的 package.json 文件中添加一个属性 proxy 和后端的 url


...
   "proxy": "https://localhost:44376"
...

现在你获取的 url 必须是相对的

fetch("/api/users")

而不是

fetch("https://localhost:44376/api/users")

【讨论】:

【参考方案4】:

从源“http://localhost:3000”访问“https://localhost:44376/api/reservation”处的 XMLHttpRequest 已被 CORS 策略阻止:对预检请求的响应未通过访问控制检查:响应中“Access-Control-Allow-Credentials”标头的值为“”,当请求的凭据模式为“包含”时,该值必须为“真”。 XMLHttpRequest 发起的请求的凭证模式由 withCredentials 属性控制。

请注意,CORS preflight request(使用 HTTP OPTIONS 方法)用于检查是否理解 CORS 协议以及服务器是否知道使用特定方法和标头。

并且 HTTP OPTIONS 请求始终是匿名的,如果您在本地项目上启用了 Windows 身份验证并禁用了匿名访问,这将导致 Web 服务器无法正确响应预检请求。

出于本地测试目的,可以先做windows认证测试,然后通过允许匿名访问单独做CORS测试。

Web API 使用 Windows 身份验证。部署到服务器时,我没有任何问题,但是当我尝试在本地运行应用程序时,出现 CORS 错误

如果已安装the IIS CORS module 并为服务器上的应用程序/站点配置了 CORS 策略,或者为您的站点启用了 Windows 身份验证和匿名身份验证,这可能是该应用程序在服务器上运行良好的原因但不在本地 IIS express 上。

【讨论】:

谢谢!这帮助我找到了答案。【参考方案5】:

尝试在每个需要 CORS 的端点上添加 [EnableCors("NAME_OF_YOUR_POLICY")]

例子:

[EnableCors("CorsPolicy")]
[Route("api/v1/test)]
public class TestApiController 

  ...

来源:

https://docs.microsoft.com/en-us/aspnet/core/security/cors?view=aspnetcore-5.0

【讨论】:

那行不通。【参考方案6】:

您的代码乍一看还不错,类似于我的一些代码,但我不喜欢这种设置,因为这些是不相关的域,这是要求browser problems:

网址:http://localhost:3000 API 网址:https://localhost:44376

验证 API 标头

首先通过一个简单的 curl 请求验证 API 的行为是否正确:

curl -i -X OPTIONS "https://localhost:44376/api/reservation" \
-H "origin: http://localhost:3000"

对于浏览器测试,我倾向于使用隐身窗口来防止旧 CORS 标头被缓存的问题。

移动到相同的站点设置

我认为 CORS 会起作用,但我知道您稍后会在 POST 请求中丢弃 cookie,因为 API cookie 将被视为第三方。请尝试更改为此设置,其中浏览器和 API 都在 mycompany.com 的 same site 中。请注意,您应该同时使用 http 或 https,尽管不同的端口都可以:

网址:http://www.mycompany.com:3000 API 网址:http://api.mycompany.com:44376

通过添加这样的条目,可以在您的主机文件中轻松注册域,将它们指向 localhost:

127.0.0.1 localhost www.mycompany.com api.mycompany.com
:1        localhost

然后,您将在带有 cookie 的浏览器中获得更好的开发者体验。您可以查看它是否会对 CORS 行为产生影响。

curl -i -X OPTIONS "http://api.mycompany.com:44376/api/reservation" \
-H "origin: http://www.mycompany.com:3000"

摘要

我不完全确定这是否会解决您的 CORS 问题,但希望它可以为您提供一些指导,以便以后有所帮助。出于兴趣,这也是我们在 Curity 推荐的设置类型,以便 cookie 确定性地工作 - 至于我们的这个与 CORS 相关的解决方案:

Code Docs

【讨论】:

设置不受我控制。这是一个内部应用程序,将部署到公司内部网络内的服务器上。 当然——但是你很可能需要 React 应用和它发送 cookie 的 API 之间的域关系。也许花一点时间调查对本地 PC 主机文件的编辑,看看它是否对您的问题有任何影响。这是一个非常快速的本地更改,因此将花费您很少的时间。另请参阅 this similar answer of mine 给那些在跨域浏览器问题上苦苦挣扎的人。【参考方案7】:

Fei Han 和 Jonathan Alfaro 让我找到了正确的方向,我终于找到了解决方案。正如韩飞在他的回答中正确指出的那样,CORS 预检请求始终是匿名的,并且它们使用 HTTP OPTIONS 方法。所以,这就是我为解决这个问题所做的工作。

    launchSettings.json 中启用匿名身份验证:
  "iisSettings": 
    "windowsAuthentication": true,
    "anonymousAuthentication": true,
    "iisExpress": 
      "applicationUrl": "http://localhost:62682",
      "sslPort": 44376
    
  ,
    创建一个如下所示的身份验证中间件,如果 http 请求具有除 OTHERS 以外的任何方法并且用户未通过身份验证,则返回 401。
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using System.Threading.Tasks;

namespace Server

    public class AuthenticationMiddleware
    
        private readonly RequestDelegate _next;

        public AuthenticationMiddleware(RequestDelegate next)
        
            _next = next;
        

        public async Task Invoke(HttpContext context)
        
            BeginInvoke(context);
            await _next.Invoke(context);
        

        private async void BeginInvoke(HttpContext context)
        
            if (context.Request.Method != "OPTIONS" && !context.User.Identity.IsAuthenticated)
            
                context.Response.StatusCode = 401;
                await context.Response.WriteAsync("Not Authenticated");
            
        
    

    使用Startup.cs中的中间件
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)

    if (env.IsDevelopment())
    
        app.UseDeveloperExceptionPage();
    
 
    app.UseSwagger();

    app.UseHttpsRedirection();

    app.UseRouting();

    app.UseMiddleware<AuthenticationMiddleware>();

    app.UseCors("CorsPolicy");

    app.UseAuthorization();

    app.UseEndpoints(endpoints =>
    
        endpoints.MapControllers();
    );

【讨论】:

【参考方案8】:

我会为开发和在本地机器上运行做两处更改:

    在添加控制器之前移动 cors 调用

    使用任何来源 像这样

            public void ConfigureServices(IServiceCollection services)
            
                services.AddDbContext<AppDbContext>(options => options
                   .UseSqlServer(Configuration.GetConnectionString("DatabaseConnection"))
                   .UseLazyLoadingProxies());
    
                services.AddScoped<IUnitOfWork, UnitOfWork>();
    
                services.AddCors(options => options.AddPolicy("CorsPolicy",
                    builder =>
                    
                        builder
                        .AllowAnyOrigin()                        
                        .AllowAnyMethod()
                        .AllowAnyHeader()
                        .AllowCredentials();
                    )); 
    
                services.AddControllers();                       
            
    

此外,如果您使用的是 IIS,您可能想看看这篇文章,因为这可能是一个预检问题:

Asp.net core web api using windows authentication - Cors request unauthorised

您可能需要将此添加到您的启动设置中,允许窗口和匿名进行预检:


  "iisSettings": 
    "windowsAuthentication": true,
    "anonymousAuthentication": true,
    "iisExpress": 
      "applicationUrl": "http://localhost:3000",
      "sslPort": 0
    
  ,
 ... more settings if any

【讨论】:

谢谢!这帮助我找到了答案。 @ataravati 如果您觉得这对您有帮助,请标记为答案。如果我需要在此答案中添加任何内容以使其更完整,也请告诉我。 请看我的回答。 @ataravati 知道了。【参考方案9】:

这很容易,这对我有用。只需为您各自的浏览器安装允许 CORS 浏览器扩展。并在发出 API 请求时将其打开。您不会收到任何错误,也不需要更改代码中的任何内容!

【讨论】:

扩展通常不起作用。

以上是关于如何使用 ASP.NET Core 解决 REACT 中的 CORS 错误的主要内容,如果未能解决你的问题,请参考以下文章

如何解决 ASP.NET Core 中的依赖问题

如何解决自动刷新在 ASP.NET Core 5 中静默失败的问题?

ASP.NET与ASP.NET Core用户验证Cookie并存解决方案

如何解决 docker-compose 环境变量不起作用 ASP.Net Core MVC

如何在 ASP.NET Core 中基于解决方案配置运行脚本

读取解决方案数据文件 ASP.Net Core