3

I have Startup, StartupProduction, and StartupDevelopment as shown below. Based on the ASP.NET Core documentation, I think I am doing this correctly.

At first, I used AllowAnyOrigin for development, but I also tested .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.

When I set the Environment to Production in Visual Studio to debug it, I face 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.

1
  • Please note that solutions (even temporary workarounds) belong as answers, not edits to the question. Commented Feb 12 at 15:47

3 Answers 3

3

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.

Sign up to request clarification or add additional context in comments.

2 Comments

Thank you @WebDev512. You are absolutely right but the IIS was not accepting the request from the domain listed in the AllowedHosts. I mentioned this in the Workaround section. The issue probebly was related to the installed hosting bundle on my machine.
Oh, Ok. I hoped that you already have installed Hosting Bundler according to .Net Core runtime version. Anyway, Is it working now?
1

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.

So, to fix the error below, if you run the App(s) on local for testing purpose with CORS, you can try to enable anonymous authentification:

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.

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

1 Comment

The user API I mentioned here is just the sample, my other actions that do not need the authentication, have the same result. But I need to check the IIS CORS module.
0

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

2 Comments

Thank you @hmd.nikoo, it seems ok but it only works for development, not production.
If I'm not mistaken, you want to change the URL in the product mode. You can use appsettings.json and appsettings.Development.json to switch between them. By using ActionFilterAttribute, you have the chance to manage security risks and use the policy for specific actions.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.