ASP.NET Core Disable CORS for specific controllers - c#

I have different set of controllers in my application (let's say A and B). CORS for A controller needs to be enabled and disabled for B controllers.
I have configured CORS via the policies in the following way:
ConfigureServices method:
services.AddCors(
options =>
{
options.AddPolicy(
"AllowCors",
builder =>
{
builder.AllowAnyOrigin().WithMethods(
HttpMethod.Get.Method,
HttpMethod.Put.Method,
HttpMethod.Post.Method,
HttpMethod.Delete.Method).AllowAnyHeader().WithExposedHeaders("CustomHeader");
});
});
services.AddMvcCore()
Configure method
app.UseCors("AllowCors");
app.UseMvc();
Set of A controllers has EnableCors attribute
[EnableCors("AllowCors")]
public class ControllerA1: Controller
CORS works for set of A controller as expected (tested via the browser). However, it also does work for B controllers! I even tried to disable CORS with DisableCors attribute explicitly:
[DisableCors]
public class ControllerB1: Controller
However, ControllerB1 controller can be requested from UI anyway.
Headers in browser for B1 contoller
Request
Provisional headers are shown
Origin: http://localhost:5000
Referer: http://localhost:5000/all
User-Agent: Mozilla/5.0 AppleWebKit Chrome/69 Safari/537
Response
Request URL: http://XX.XX.XX.XX/getall
Request Method: GET
Status Code: 200 OK
Remote Address: XX.XX.XX.XX:80
Referrer Policy: no-referrer-when-downgrade
Access-Control-Allow-Origin: *
Access-Control-Expose-Headers: CustomCount
Content-Type: application/xml; charset=utf-8
Server: Kestrel
Could you please advise how to disable CORS for specific controllers?

In your example, you've done two things of note in setting up the WebHost:
Created a custom CORS policy named AllowCors.
Added the CORS middleware to the pipeline, which uses AllowCors as its policyName.
Here's a snippet of the Invoke function that gets called for the CORS middleware:
public async Task Invoke(HttpContext context)
{
if (context.Request.Headers.ContainsKey(CorsConstants.Origin))
{
var corsPolicy = _policy ?? await _corsPolicyProvider?.GetPolicyAsync(context, _corsPolicyName);
if (corsPolicy != null)
{
var corsResult = _corsService.EvaluatePolicy(context, corsPolicy);
_corsService.ApplyResult(corsResult, context.Response);
...
In this snippet, _policy is null and _corsPolicyName is AllowCors. Because AllowCors is the name of a valid policy that was added using AddCors, this results in the CORS middleware applying the revelant CORS headers for all requests.
In your example, you've also used both [EnableCors(...)] and [DisableCors], which are MVC authorisation filters. By doing this, you're mostly just telling MVC to take care of CORS, which is independent of the CORS middleware you've added to the WebHost's pipeline.
This combination of MVC and CORS middleware is what is causing your unexpected results. The middleware is adding the CORS headers to your request regardless of whether or not you're asking it not to by using the [DisableCors] attribute - the CORS middleware has no idea that this MVC concept (a filter) even exists.
Based on this information, you can fix your issue in one of two ways:
Remove the policyName parameter from your call to UseCors.
Remove the UseCors call itself.
With option 1, the UseCors middleware will use the default policy, if it's been configured using AddDefaultPolicy on the CorsOptions passed into the AddCors delegate.
With option 2, the CORS middleware is simply excluded from the pipeline. This will also work in your example, because you've used [EnableCors(...)] where you need it. This also means that you don't need to use [DisableCors] at all - it'll default to not adding the CORS headers.
This raises the question: When would [DisableCors] be useful? As an example, consider the following basic controller:
[EnableCors("AllowCors")]
public class ExampleController : ControllerBase
{
public IActionResult Action1() =>
...
public IActionResult Action2() =>
...
}
It's clear that in this example, both Action1 and Action2 will set the CORS headers. If you didn't want Action2 to set the headers, you could annotate it with [DisableCors].

The order of the app.useCors is important
//...
app.UseRouting();
app.UseCors("customPolicy");
app.UseEndpoints(...)
//...

Related

Failed http request WebApi using Angular

I am trying to connect a service created in .net from angular but I get an error with CORS, I have looked for many links but none have helped me since most of the solutions are for .NET CORE and I am using standard .net .
call from angular:
return this.http.post('http://localhost:50112/api/auth', userdata).toPromise();
Api:
public class AuthController : ApiController
{
public async Task<IHttpActionResult> Auth(User userdata)
{
var result = await bllUser.auth(userdata);
return Ok(result);
}
}
and this error:
Access to XMLHttpRequest at 'http://localhost:50461/api/auth' from origin 'http://localhost:4200' 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.
I also tried adding the config.EnableCors statement in my webapiconfig file but it tells me that that statement does not exist
I would appreciate your help, no solution has served me
To use enable cors
Install CORS to the API project "Install-Package Microsoft. Asp. Net. WebApi. Cors".
And change your register method
public static void Register(HttpConfiguration config)
{
var cors = new EnableCorsAttribute("www.example.com", "*", "*");
config.EnableCors(cors);
// ...
}

AllowAnyMethod works for some API calls but not for others

I have the form mentioned in this question, but when I submit it I get
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://localhost:1113/api/loans. (Reason: CORS header 'Access-Control-Allow-Origin' missing).
and
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://localhost:1113/api/loans. (Reason: CORS request did not succeed).
I had fixed this for another API call previously by adding this to me API's Configure in Startup:
app.UseCors(options => options.WithOrigins("*").AllowAnyMethod());
But now for some reason it is blocking the call where the action is
// POST api/loans
[HttpPost]
public void Post(Loan loan)
{
_context.Loans.Add(loan);
_context.SaveChanges();
}
Why?
This is a vague question so I'll give a few tips on what it could be.
First start off by Turning on all Exceptions
There's a chance you're getting an exception before the cors happens so you application
is returning an error response before it can add the cors headers.
.Net-Core require attribute for resolving how to model bind the data. So you're http post method should require either [FromForm] or [FromBody] attributes
[HttpPost]
public void Post([FromForm] Loan loan)
{
_context.Loans.Add(loan);
_context.SaveChanges();
}
Make sure you are actually using you're cors policy. Unless your using an old version of .Net Core you should be implementing your cors policy from the Configure Services method and not the configure method
Try implementing your policy like so:
services.AddCors(options =>
{
options.AddPolicy(DEFAULT_POLICY_NAME, policy =>
{
policy.SetIsOriginAllowedToAllowWildcardSubdomains()
.AllowAnyOrigin()
.AllowAnyHeader()
.AllowAnyMethod()
.AllowCredentials();
});
});
Then in your configure method you just use the policy name
app.UseCors(DEFAULT_POLICY_NAME);
Try using [FromBody]
public void Post([FromBody] Loan loan)
also when you try to send use JSON.stringify instead of modle directly,
this.http.post('http://localhost:1113/api/loans', JSON.stringify(this.model), config).subscribe(data => {
console.log(data);
});

CORS failing for POST in web api

Setting up CORS for a simple web api in a .NET core app I have this:
public void ConfigureServices(IServiceCollection services)
{
services.AddCors(options =>
{
options.AddPolicy("GetPolicy",
builder => builder.AllowAnyOrigin()
.WithMethods("GET")
.WithHeaders("x-mycustomheader-cors"));
options.AddPolicy("PostPolicy",
builder => builder.AllowAnyOrigin()
.WithMethods("POST")
.WithHeaders("x-mycustomheader-cors"));
});
services.AddMvc();
}
I have a get endpoint that's set up like this and works fine:
[HttpGet]
[EnableCors("GetPolicy")]
[AuthorizationFilter]
public IEnumerable<MyModel> Get()
{
//...
}
Which works fine, but this (in a different controller):
[HttpPost]
[EnableCors("PostPolicy")]
[AuthorizationFilter]
public void Post([FromBody]MyOtherModel[] models)
{
//...
}
Fails with:
Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
If I change the PostPolicy to:
options.AddPolicy("PostPolicy",
builder => builder.AllowAnyOrigin().AllowAnyMethod().AllowAnyHeader());
Then POST will work fine cross-domain, but I'd prefer to not just allow anything. So what am I missing here?
Experimenting a bit, it seemed the AllowAllHeaders was the necessary part, so I dug a bit deeper to look at what headers are being passed and strangely, it seems it's the Content-Type header that it was tripping up on.
So this worked (from Chrome in a JSFiddle):
options.AddPolicy("PostPolicy",
builder => builder.AllowAnyOrigin()
.WithMethods("POST")
.WithHeaders("x-chmura-cors", "Content-Type"));
Which is surprising since I would have thought the standard headers (like Content-Type) wouldn't need to be explicitly included.
The error message was, of course, completely unhelpful.
Edit
So according to this: https://learn.microsoft.com/en-us/aspnet/core/security/cors?view=aspnetcore-2.1#preflight-requests (thanks to #spender), the problem is that Content-Type only passes automatically if it's value is:
The Content-Type header, if set, has one of the following values:
application/x-www-form-urlencoded
multipart/form-data
text/plain
I had mine set to application/json and I guess that was what it didn't like.

CORS not working with route

I have an issue with an endpoint on my web api. I have a POST method that is not working due to:
Response to preflight request doesn't pass access control check: No
'Access-Control-Allow-Origin' header is present on the requested
resource. Origin 'http://localhost:3000' is therefore not allowed
access. The response had HTTP status code 405.
I cannot see why that is not working since I have plenty of methods that are working indeed with the same COSR configuration. The only difference is that this method has a specified route, as you can see below:
// POST: api/Clave
[EnableCors(origins: "*", headers: "*", methods: "*", SupportsCredentials = true)]
[Route("{id:int}/clave")]
[HttpPost]
public HttpResponseMessage Post(int id, [FromBody]CambioClaveParameters parametros)
{
UsuarioModel usuario = SQL.GetUsuario(id);
if (Hash.CreateMD5(parametros.ViejaClave) != usuario.Clave.ToUpper())
{
return Request.CreateResponse(HttpStatusCode.BadRequest);
}
else if (Hash.CreateMD5(parametros.ViejaClave) == usuario.Clave.ToUpper())
{
SQL.ModificarClaveUsuario(id, Hash.CreateMD5(parametros.NuevaClave));
return Request.CreateResponse(HttpStatusCode.OK);
}
else
{
return Request.CreateResponse(HttpStatusCode.InternalServerError);
}
}
Any Ideas of why this is happening?.
Thanks!.
Based upon the word "preflight" in your message, this is an OPTIONS verb issue. If you examine the requests and responses, I believe you'll see that the request directly before your POST is an OPTIONS request. The OPTIONS request is asking the server what methods are allowed to be called. If you haven't enabled an OPTIONS response, or your OPTIONS response doesn't include the POST method for that Uri, you'll get this response.
Here's a link describing the concept (see section Preflight CORS Requests)
https://msdn.microsoft.com/en-us/magazine/dn532203.aspx
To account for this bypassing everything OPTIONS is designed to do, you can add code similar to this (don't be a cargo-cult programmer) to a new or existing module's BeginRequest method:
if (context.Request.HttpMethod.ToLower() == "options")
{
var origin = context.Request.Headers["origin"];
context.Response.StatusCode = 200;
context.Response.AddHeader("Access-Control-Allow-Origin", origin);
context.Response.AddHeader("Access-Control-Allow-Credentials", "true");
context.Response.AddHeader("Access-Control-Allow-Methods", "POST, GET, PUT, DELETE, OPTIONS");
context.Response.End();
}
Ideally, though, you would want to programmatically determine whether the request is a valid, and if so, then output a response customized for what is actually allowed.
if you are using web api just create one class at root level name it Startup.cs If you can try adding following code in your startup and see if that works. This code will inject cors middelware in ur application pipeline. You probably need to add owin via nuget. Give it a try
[assembly: OwinStartup(typeof(MyProject.API.Startup))]
namespace MyProject.API
{
public class Startup
{
public void Configuration(IAppBuilder app)
{
app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);
app.UseWebApi(WebApiConfig.Register());
}
}
}
Your Web API response is clearly a 405, which indicates that you are calling an URI that does not support your HTTP Method (in this case POST).
Starting from this you need to understand why your URI does not support POST. The most probable answer is that you are calling the wrong URI. The fact that you are getting a CORS error is not the root of your problem and derives from the fact that the wrong URI you are calling does not set any Access-Control-Allow-Origin header.
Looking at your controller method:
[EnableCors(origins: "*", headers: "*", methods: "*", SupportsCredentials = true)]
[Route("{id:int}/clave")]
[HttpPost]
public HttpResponseMessage Post(int id, [FromBody]CambioClaveParameters parametros)
It appears to me that you are using a Route attribute, but not setting a RoutePrefix attribute in your controller class.
This means that the correct URI for your method is the following one:
http://localhost:xxxx/1/clave
And not, as you might think, that one:
http://localhost:xxxx/api/Clave/1/clave
If you want to access your resource using the second URI you need to put a new RoutePrefix attribute in your Controller:
[RoutePrefix("api/Clave")]
public class ClaveController : ApiController {
//..
}
Hope you are doing good !
you can use below code that will allow origin access on each request response.
protected void Application_BeginRequest(object sender, EventArgs e)
{
HttpContext.Current.Response.AddHeader("Access-Control-Allow-Origin", *");}
for more reference you can get help from below link.
http://enable-cors.org/server_aspnet.html

ASP.NET MVC 6 handling errors based on HTTP status code

I want to display different error messages for each status code e.g:
400 Bad Request
403 Forbidden
500 Internal Server Error
404 Not Found
401 Unauthorized
How can I achieve this in the new ASP.NET MVC 6 applications? Can I do this using the built in UseErrorHandler method?
application.UseErrorHandler("/error");
Also, I noticed that even with the above handler, entering a non-existent URL e.g. /this-page-does-not-exist, causes an ugly 404 Not Found error page from IIS. How can this also be handled?
In MVC 5 we have had to use the system.web customerrors section for ASP.NET and the system.webServer httpErrors section in the web.config file but it was difficult to work with an unwieldy, with lots of very strange behaviour. Does MVC 6 make this a lot simpler?
You could use the StatusCodePagesMiddleware for this. Following is an example:
public void Configure(IApplicationBuilder app, ILoggerFactory loggerFactory)
{
app.UseStatusCodePagesWithReExecute("/StatusCodes/StatusCode{0}");
app.UseMvcWithDefaultRoute();
Controller which handles the status code requests:
public class StatusCodesController : Controller
{
public IActionResult StatusCode404()
{
return View(viewName: "NotFound"); // you have a view called NotFound.cshtml
}
... more actions here to handle other status codes
}
Some Notes:
Check other extension methods like UseStatusCodePagesWithRedirects
and UseStatusCodePages for other capabilities.
I tried having StatusCode as a query string in my example, but looks like this
middleware doesn't handle query strings, but you can take a look at
this code and fix this issue.
How can I achieve this in the new ASP.NET MVC 6 applications? Can I do this using the built in UseErrorHandler method?
Quick answer: Not in an elegant fashion.
Explanation/Alternative: To start lets first look at what the UseErrorHandler method is actually doing: https://github.com/aspnet/Diagnostics/blob/6dbbe831c493e6e7259de81f83a04d1654170137/src/Microsoft.AspNet.Diagnostics/ErrorHandlerExtensions.cs#L25 which adds the following middleware: https://github.com/aspnet/Diagnostics/blob/6dbbe831c493e6e7259de81f83a04d1654170137/src/Microsoft.AspNet.Diagnostics/ErrorHandlerMiddleware.cs Note lines 29-78 (the invoke method)
The invoke method is executed whenever a request comes in (controlled by the location of your application.UseErrorHandler("...") in your Startup.cs). So the UseErrorHandler is a glorified way of adding a custom middleware: middleware = component that can act on an http request.
Now with that background, if we wanted to add our own error middleware that differentiated requests. We could do this by adding a similar middleware that's like the default ErrorHandlerMiddleware by modifying these lines: https://github.com/aspnet/Diagnostics/blob/6dbbe831c493e6e7259de81f83a04d1654170137/src/Microsoft.AspNet.Diagnostics/ErrorHandlerMiddleware.cs#L48-L51 With that approach we could control the redirect path based on the status code.
In MVC 5 we have had to use the system.web customerrors section for ASP.NET and the system.webServer httpErrors section in the web.config file but it was difficult to work with an unwieldy, with lots of very strange behaviour. Does MVC 6 make this a lot simpler?
Answer: It sure does :). Just like the above answer the fix lies in adding middleware. There's a shortcut to adding simple middleware via the IApplicationBuilder in your Startup.cs; at the end of your Configure method you can add the following:
app.Run(async (context) =>
{
await context.Response.WriteAsync("Could not handle the request.");
// Nothing else will run after this middleware.
});
This will work because it means that you reached the end of your http pipeline without the request being handled (since it's at the end of your Configure method in Startup.cs). If you want to add this middleware (in the quick fashion) with the option to execute middleware after you, here's how:
app.Use(async (context, next) =>
{
await context.Response.WriteAsync("Could not handle the request.");
// This ensures that any other middelware added after you runs.
await next();
});
Hope this helps!

Categories