简体   繁体   中英

Enable CORS in ASP.Net Core 5 WebAPI

There are millions of articles and questions related to this issue and yet I cannot find what's wrong with my code. I have Startup , StartupProduction , and StartupDevelopment as the following. Also, I am using ASP.Net Core 5 , and based on the documentation I think I am doing this correctly.

FYI, at first, I used AllowAnyOrigin for development but I also test .WithOrigins("http://localhost:3000") and it works fine. My backend runs under https://localhost:44353 in development and under https://api.example.com in production.

public class Startup
{
    protected const string CorsPolicyName = "CorsPolicyName";

    public virtual void ConfigureServices(IServiceCollection services)
    {
        services.AddControllers()
            .AddJsonOptions(options =>
            {
                options.JsonSerializerOptions.Converters.Add(
                    new System.Text.Json.Serialization.JsonStringEnumConverter());
            });

        services.AddABunchOfOtherServices();
    }

    public virtual void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        app.UseHttpsRedirection();
        app.UseStaticFiles();
        app.UseRouting();
        app.UseCors(CorsPolicyName);
        app.UseAuthentication();
        app.UseAuthorization();

        app.UseMiddleware<CheckUserConfirmedMiddleware>();

        app.UseEndpoints(endpoints =>
        {
            endpoints.MapControllerRoute
            (
                name: "default",
                pattern: "{controller=Home}/{action=Index}/{id?}"
            )
            .RequireCors(CorsPolicyName);
        });
    }
}

public class StartupProduction : Startup
{
    public override void ConfigureServices(IServiceCollection services)
    {
        services.AddCors(options =>
        {
            options.AddPolicy(
                CorsPolicyName,
                policy => policy
                    .WithOrigins("https://example.com", "http://example.com")
                    //.WithOrigins(Configuration.GetValue<string>("AllowedHosts").Split(';').ToArray())
                    .AllowAnyMethod()
                    .AllowAnyHeader());
        });

        base.ConfigureServices(services);
    }

    public override void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        app.UseMiddleware(typeof(ErrorHandlingMiddleware));

        // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
        app.UseHsts();

        base.Configure(app, env);
    }
}

public class StartupDevelopment : Startup
{
    public override void ConfigureServices(IServiceCollection services)
    {
        services.AddCors(options =>
            options.AddPolicy(
                CorsPolicyName,
                policy =>
                    policy
                        //.AllowAnyOrigin()
                        .WithOrigins("http://localhost:3000")
                        .AllowAnyMethod()
                        .AllowAnyHeader()
            )
        );

        base.ConfigureServices(services);

        services.AddSwaggerGen(....);
    }

    public override void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        app.UseMiddleware<DevelopmentErrorHandlingMiddleware>();

        base.Configure(app, env);

        app.UseSwagger();

        app.UseSwaggerUI(options =>
        {
            options.SwaggerEndpoint("swagger/v1/swagger.json", "API v1");
            options.RoutePrefix = string.Empty;
        });
    }
}

I also tried the default policy .

Update

I have set the Environment to Production in the visual studio to debug it and now I am facing the same issue in development.

Access to fetch at 'https://localhost:44353/api/v1/User' from origin 'http://localhost:3000' 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. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.

Workaround solution

I notice that it is the IIS blocking the request. It only works when I have "AllowedHosts": "*", in my appsettings.json . So, as a workaround, I have added "MyRandomKey": "https://example.com", in my appsettings.json and use the following in my Startup .

services.AddCors(options =>
                options.AddPolicy(
                    CorsPolicyName,
                    policy =>
                        policy
                            .WithOrigins(Configuration.GetValue<string>("MyRandomKey").Split(";").ToArray())
                            .AllowAnyMethod()
                            .AllowAnyHeader()
                )
            );

AllowedHosts & CORS are different.

AllowedHosts is for host filtering so even if you have configured CORS Policy in your application but didn't allowed host then IIS will reject the request.

Please refer this link: Difference between AllowedHosts in appsettings.json and UseCors in .NET Core API 3.x

And by default it's * but you can change it to according to your requirements. In your case you can set "api.example.com" or if you want to allow also from localhost then "api.example.com;localhost". Once you set it then IIS will start accepting requests from those domains.

Once IIS will start accepting request then your application level configured CORS policy will be applied and work. So basically the CORS is to allow access of resources in your WebAPI.

I think it's Ok, and also, you can get origins from DB or JSON files. also, you can use ActionFilterAttribute and this part of the code

    var csp = "default-src 'self' http://localhost:3000; object-src 'none'; frame-ancestors 'none'; sandbox allow-forms allow-same-origin allow-scripts; base-uri 'self';";

if (!context.HttpContext.Response.Headers.ContainsKey("Content-Security-Policy"))
{
    context.HttpContext.Response.Headers.Add("Content-Security-Policy", csp);
}

if (!context.HttpContext.Response.Headers.ContainsKey("X-Content-Security-Policy"))
{
    context.HttpContext.Response.Headers.Add("X-Content-Security-Policy", csp);
}

From this doc about CORS preflight request , you can find following information:

A CORS preflight request is used to determine whether the resource being requested is set to be shared across origins by the server. And The OPTIONS requests are always anonymous, server would not correctly respond to the preflight request if anonymous authentification is not enabled.

Access to fetch at 'https://localhost:44353/api/v1/User' from origin 'http://localhost:3000' 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. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.

To fix the above issue, if you run the App(s) on local for testing purpose with CORS, you can try to enable anonymous authentification.

Besides, if your App(s) are hosted on IIS, you can try to install IIS CORS module and configure CORS for the app.

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