18

I am trying to setup 2 CORS policies. One as an api default and the other to use on Controllers as I need them. The reason I want to do this is because I have an endpoint that takes in an object with email info and sends an email (to use with the contact me box on my webpage) and have it only accept requests from my domain.

My startup.cs file snippet:

public void ConfigureServices(IServiceCollection services)
        {
            services.AddCors(options =>
            {
                options.AddPolicy("Example",
                    builder => builder.WithOrigins("http://www.example.com"));
                options.AddPolicy("AllowAll",
                    builder => builder.AllowAnyOrigin());
            });

            services.AddMvc();
            //other configure stuff
        }


 public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
    {
        app.UseCors(builder =>
        {
            builder.AllowAnyHeader();
            builder.AllowAnyMethod();
            builder.WithOrigins("AllowAll");
        });

        app.UseMvcWithDefaultRoute();
    }

My emailcontroller.cs file:

using System.Threading.Tasks;
using MyAPI.Models;
using MyAPI.Services;
using Microsoft.AspNetCore.Cors;
using Microsoft.AspNetCore.Mvc;

namespace MyAPI.Controllers
{
    [Produces("application/json")]
    [Route("api/Email")]
    [EnableCors("Example")]
    public class EmailController : Controller
    {
        private readonly IEmailSender _emailSender;

        public EmailController(IEmailSender emailSender)
        {
            _emailSender = emailSender;
        }

        [HttpPost]
        public async Task Post([FromBody] Email email)
        {
            await _emailSender.SendEmailAsync(email);
        }
    }

}

Javascript used to send email:

function sendEmail(email)
{
    var urlToApi = "http://<ipToApi>:5000/api";
    $.ajax({
            method: "POST",
            contentType: "application/json; charset=utf-8",
            data: JSON.stringify(email),     
            url: urlToApi + "/email/",
            success: function(data) {  
                console.log(data);
                console.log('probably sent');
            },
            error: function(jqXHR, textStatus, errorThrown){
                console.log(textStatus);
                alert("There was like, an error doing that");
            }
        });
}

This is what I get trying to send from http://www.example.com

XMLHttpRequest cannot load http://<ipToApi>:5000/api/email/. 
Response to preflight request doesn't pass access control check: 
No 'Access-Control-Allow-Origin' header is present on the requested
 resource. Origin 'http://www.example.com' is therefore not allowed access.

EDIT

This works:

services.AddCors(options =>
            {
                options.AddPolicy("Example",
                    builder => builder.WithOrigins("http://www.example.com")
                                        .AllowAnyHeader()
                                        .AllowAnyMethod());
                options.AddPolicy("AllowAll",
                    builder => builder.AllowAnyOrigin()
                                        .AllowAnyHeader()
                                        .AllowAnyMethod());
            });
Jrow
  • 1,026
  • 2
  • 12
  • 31
  • 1
    You're setting your origin as "AllowAll" – Mardoxx May 15 '17 at 18:16
  • @Mardoxx I thought that would just set the default. If I comment all that out can I just use the [EnableCors("mypolicy")] on all my controllers? – Jrow May 15 '17 at 18:17
  • 1
    You should be using `app.UseCors("AllowAll");` – Mardoxx May 15 '17 at 18:18
  • 1
    You are also not allowing any methods/headers. CORS spec says you don't set any headers if any checks fails to pass (at least that is how ASPNET Core interprets it!) So that is why I believe you get the generic `...-Allow-Origin not present` error. If you add in `AllowAnyHeader` and `AllowAnyMethod` to both policies it may work as expected. – Mardoxx May 15 '17 at 18:20
  • 1
    @Mardoxx thanks! if you post that as an answer i'll accept it – Jrow May 15 '17 at 18:26

2 Answers2

14

To set a default CORS policy use app.UseCors(string policyName) overload.

Your CORS requests will be failing because you are rejecting all headers and methods. From what I read, the CORS specification states that you shouldn't set any headers at all if any of the checks fail. See implementation here, this is most likely why your client will be receiving the standard No 'Access-Control-Allow-Origin' header is present error, as no headers are added at all, even though the Origin check passes.

The following should work as expected, and your [EnableCors(...)] decorator should override the default!

public void ConfigureServices(IServiceCollection services)
{
    services.AddCors(options =>
    {
        options.AddPolicy("Example",
            builder => builder.WithOrigins("http://www.example.com")
                                .AllowAnyHeader()
                                .AllowAnyMethod());
        options.AddPolicy("AllowAll",
            builder => builder.AllowAnyOrigin()
                                .AllowAnyHeader()
                                .AllowAnyMethod());
    });

    services.AddMvc();
    //other configure stuff
}


public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
    app.UseCors("AllowAll"); //Default

    app.UseMvcWithDefaultRoute();
}

You may need to add .AllowCredentials() to your policies, but I am not sure. Read here perhaps?

Community
  • 1
  • 1
Mardoxx
  • 4,372
  • 7
  • 41
  • 67
  • 2
    I don't think the controller level [EnableCors] overrides the default. This only appears to work because the default is to allow all. – Mike Bennett Aug 16 '18 at 15:38
  • 2
    Using `app.UseCors("AllowAll");` uses the middleware which fires before the mvc cors attrbutes , and is not overridden by them . This answer I think is a little misleading as yes it only works as 2 cors policys are applied one after another, this helped me in the end - https://andrewlock.net/a-deep-dive-in-to-the-asp-net-core-cors-library/ – Tom May 07 '19 at 10:10
7

Configure Method

app.UseRouting();
app.UseCors("CorsApi");
app.UseAuthentication();

ConfigureServices method

services.AddCors(options =>
    {
        options.AddPolicy("Policy1",
            builder => builder.WithOrigins("http://localhost:4200", "http://mywebsite.com")
        .AllowAnyHeader()
        .AllowAnyMethod());
        options.AddPolicy("Policy2",
            builder => builder.WithOrigins("http://localhost:4300", "http://yourwebsite.com")
        .AllowAnyHeader()
        .AllowAnyMethod());
    });
tfa
  • 1,643
  • 16
  • 18