简体   繁体   中英

Cross Origin preflight request in Nginx Proxy

Getting this error when accessing from browser

Access to XMLHttpRequest at 'https://api.example.com/users/authenticate' from origin 'https://example.com' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource

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 Conf File

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;
  }
}

Have enabled Cors Policy in the controllers also By adding bellow code to controller top

[EnableCors("CorsApi")]

Function for sending request in frontend:

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;
};

Startup Setting for locahost server:

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

Service Starting the Locahost Server:

[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

Can anyone please point it out where i am going wrong bit new the nginx stuff whereas another project when hosted with normal iis all works good.

I don't know if the CORS headers could be added from the .NET application itself, or is that one approach is better, but to add them via nginx you can use the following:

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';
    }
}

If you need to support additional methods ( PUT , DELETE , etc.), add them to the methods list.

Update

If your XMLHttpRequest is being made with credentials , you cannot use * as the Access-Control-Allow-Origin header value. For that case you can dynamically set the Access-Control-Allow-Origin to the request's Origin header value:

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';
    }
}

h have same problem: without add header to nginx can solve it:

nginx config:

server {
    listen        80;
    server_name   example.com;
    location / {
     
        proxy_pass         http://127.0.0.1:5000;
        proxy_http_version 1.1;
        proxy_set_header   Upgrade $http_upgrade;
        proxy_set_header   Connection keep-alive;
        proxy_set_header   Host $host;
        proxy_cache_bypass $http_upgrade;
        proxy_set_header   X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header   X-Forwarded-Proto $scheme;
    }
}

add this line to program.cs(.net core 6) or startup.cs (.net core 3.1 or 5):

//CORS configuration

app.UseForwardedHeaders(new ForwardedHeadersOptions
{
    ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto
});

//Auth... configuration

this make proxy to forward all headers and not need to add headers on nginx again.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM