【问题标题】:Cross Origin preflight request in Nginx ProxyNginx 代理中的跨域预检请求
【发布时间】:2021-03-01 12:00:57
【问题描述】:

从浏览器访问时出现此错误

CORS 政策已阻止从源“https://example.com”访问“https://api.example.com/users/authenticate”处的 XMLHttpRequest:对预检请求的响应未通过访问控制检查:请求的资源上没有“Access-Control-Allow-Origin”标头

Startup.cs

using System;
using System.Text;
using BackendRest.Helper;
using BackendRest.Models;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.HttpOverrides;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.IdentityModel.Tokens;

namespace BackendRest
{
    public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }
        readonly string CorsApi = "_CorsApi";
        public IConfiguration Configuration { get; }
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddCors(options =>
            {
                options.AddPolicy(CorsApi,
                    builder =>
                    {
                        builder
                        .AllowAnyOrigin()
                        .AllowAnyMethod()
                        .AllowAnyHeader();
                    });
            });
            services.AddControllers().AddNewtonsoftJson();
            services.AddDbContext<backenddbContext>(x => x.UseMySql(Configuration.GetConnectionString("DefaultConnection")));
            services.AddScoped<IUserHelper, UserHelper>();
            services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme).AddJwtBearer(options =>
            {
                options.RequireHttpsMetadata = false;
                options.SaveToken = true;
                options.TokenValidationParameters = new TokenValidationParameters()
                {
                    ClockSkew = TimeSpan.Zero,
                    ValidateLifetime = true,
                    ValidateIssuer = true,
                    ValidateAudience = true,
                    ValidAudience = Configuration["Jwt:Audience"],
                    ValidIssuer = Configuration["Jwt:Issuer"],
                    IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["Jwt:Key"]))
                };
            });
        }
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            app.UseHttpsRedirection();
            app.UseRouting();
            app.UseCors(CorsApi);
            app.UseForwardedHeaders(new ForwardedHeadersOptions
            {
                ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto
            });
            app.UseAuthentication();
            app.UseAuthorization();
            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllers();
            });
        }
    }
}

Nginx 配置文件

server {
    #listen        80;
    listen                 *:443 ssl;
    ssl_certificate        /etc/ssl/example.com.pem;
    ssl_certificate_key    /etc/ssl/example.com.key;
    if ($host != "api.example.com") {
  return 404;
 }
    server_name            api.example.com;
    location / {
    proxy_pass      https://localhost:5001;
    proxy_set_header Host $host;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_http_version 1.1;
    proxy_set_header   Upgrade $http_upgrade;
    proxy_set_header   Connection keep-alive;
    proxy_cache_bypass $http_upgrade;
    proxy_set_header   X-Forwarded-Proto $scheme;
  }
}

在控制器中也启用了 Cors 策略通过在控制器顶部添加波纹管代码

[EnableCors("CorsApi")]

前端发送请求函数:

export const login = async ({ username, password }) => {
  const result = await axios.post(
    `${BASE_URL}/users/authenticate`,
    JSON.stringify({ username, password }),
    {
      headers: {
        'Content-Type': 'application/json',
      },
    }
  );

  return result;
};

locahost 服务器的启动设置:

"Kestrel": {
    "Endpoints": {
      "HTTPS": {
        "Url": "https://localhost:5001",
        "Certificate": {
          "Path": "/etc/ssl/example.pfx",
          "Password": "james343"
        }
      }
    }
  }

服务启动Locahost服务器:

[Unit]
Description=My first .NET Core application on Ubuntu

[Service]
WorkingDirectory=/home/ubuntu/example
ExecStart=/usr/bin/dotnet /home/ubuntu/example/BackendRest.dll
Restart=always
RestartSec=10 # Restart service after 10 seconds if dotnet service crashes
SyslogIdentifier=offershare-web-app
Environment=ASPNETCORE_ENVIRONMENT=Production
Environment=DOTNET_PRINT_TELEMETRY_MESSAGE=false
Environment=ASPNETCORE_HTTPS_PORT=5001
Environment=ASPNETCORE_URLS=https://localhost:5001

[Install]
WantedBy=multi-user.target

任何人都可以指出我在哪里出错了一点新的 nginx 东西,而另一个项目在使用普通 iis 托管时一切正常。

【问题讨论】:

  • 应该只允许来自https://example.com 还是来自任何地方的https://api.example.com 请求? api.example.com (GET, POST, ...) 使用了哪些 HTTP 方法?
  • @IvanShatsky 请求现在允许用于启动文件中的所有源和所有方法:options.AddPolicy(CorsApi,builder =&gt;{builder .AllowAnyOrigin().AllowAnyMethod().AllowAnyHeader();});

标签: asp.net-core nginx asp.net-web-api cors nginx-reverse-proxy


【解决方案1】:

我不知道是否可以从 .NET 应用程序本身添加 CORS 标头,还是一种方法更好,但要通过 nginx 添加它们,您可以使用以下方法:

server {
    ...
    location / {
        if ($request_method = OPTIONS) {
            add_header Access-Control-Allow-Origin '*';
            add_header Access-Control-Allow-Methods 'GET, POST, OPTIONS';
            add_header Content-Type text/plain;
            add_header Content-Length 0;
            return 204;
        }
        ... # your current configuration here
        add_header Access-Control-Allow-Origin '*';
        add_header Access-Control-Allow-Methods 'GET, POST, OPTIONS';
    }
}

如果您需要支持其他方法(PUTDELETE 等),请将它们添加到方法列表中。

更新

如果您的 XMLHttpRequest 正在生成 with credentials,则您将 cannot use * 作为 Access-Control-Allow-Origin 标头值。对于这种情况,您可以将 Access-Control-Allow-Origin 动态设置为请求的 Origin 标头值:

server {
    ...
    location / {
        if ($request_method = OPTIONS) {
            add_header Access-Control-Allow-Origin $http_origin;
            add_header Access-Control-Allow-Methods 'GET, POST, OPTIONS';
            add_header Content-Type text/plain;
            add_header Content-Length 0;
            return 204;
        }
        ... # your current configuration here
        add_header Access-Control-Allow-Origin $http_origin;
        add_header Access-Control-Allow-Methods 'GET, POST, OPTIONS';
    }
}

【讨论】:

猜你喜欢
  • 2021-03-12
  • 2013-10-24
  • 2023-03-30
  • 2015-08-12
  • 2011-03-30
  • 2012-04-02
  • 2014-04-02
  • 2015-08-25
相关资源
最近更新 更多