I'm trying to call my C# web-api from my Vue webapplication but I encounter the following error:
Access to XMLHttpRequest at 'http://www.api.example.com/'
from origin 'http://www.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.
The following code snippet shows how I'm calling the rest-api with use of axios.
import axios from 'axios'
const client = axios.create({
baseURL: 'http://www.api.example.com',
json: true,
withCredentials: true
})
export default {
async execute(method, resource, data) {
return client({
method,
url: resource,
data,
headers: {}
}).then(req => {
return req
})
},
myFunc(data) {
return this.execute('post', '/', data)
}
}
The web-api with the POST request method is as follows:
[EnableCors("VueCorsPolicy")]
[Route("api/[controller]")]
[ApiController]
public class MyController : ControllerBase
{
[HttpPost]
public async Task<int> Post([FromBody] Data data)
{
// stuff
}
}
I have also added a CORS to my "ConfigureServices" method in the Startup.cs file.
services.AddCors(options =>
{
options.AddPolicy("VueCorsPolicy", builder =>
{
builder
.WithOrigins("http://www.example.com")
.AllowAnyHeader()
.AllowAnyMethod()
.AllowCredentials();
});
});
And lastly I have also added to the "Configure" method in the Startup.cs file:
app.UseCors("VueCorsPolicy");
CORS is a security mechanism, that cannot be overcome by simply modifying your code. The server has to be set so that it allows the requests from your source - so, if you control the server you can do it.
However, there are some solutions that help you during development phase, like cors-anywhere.herokuapp.com.
You should add it before the baseURL in your code, like this:
baseURL: 'https://cors-anywhere.herokuapp.com/http://www.api.example.com'.
This is NOT a solution for production, only for development.
You can host your own cors-anywhere app, more on this: https://www.npmjs.com/package/cors-anywhere
.WithOrigins("http://www.thomasleoblok.dk/") this is where your problem is, it should be .WithOrigins("http://www.example.com") since it is example.com you want to allow to make requests, it you want to allow any site you can change it to .WithOrigins("*")
if you are trying locally you must open the origin localhost, otherwise the BE will always return a cors error as localhost != http://www.thomasleoblok.dk/
for testing I suggest you enable AllowAnyOrigin()
example:
services.AddCors(options =>
{
options.AddPolicy("VueCorsPolicy", builder =>
{
builder
.AllowAnyOrigin()
.AllowAnyHeader()
.AllowAnyMethod()
.AllowCredentials();
});
});
Related
I'm having some issues with React consuming my web API. I'm receiving the following error when submitting a POST request:
Access to XMLHttpRequest at 'https://localhost:7078/api/v1/Authentication/token' 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.
However, CORS seems to be setup. I followed the instructions here: https://learn.microsoft.com/en-us/aspnet/core/security/cors?view=aspnetcore-7.0:
Program.cs
using HealthChecks.UI.Client;
using Microsoft.AspNetCore.Diagnostics.HealthChecks;
using WatchDog;
using AspNetCoreRateLimit;
using PetTracker.StartupConfig;
using Microsoft.AspNetCore.Authorization;
using Microsoft.IdentityModel.Tokens;
using System.Text;
using Microsoft.OpenApi.Models;
using PetTracker.HealthChecks;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.AddServices();
builder.Services.AddCors(opts =>
{
opts.AddDefaultPolicy(policy =>
{
policy.AllowAnyOrigin().AllowAnyHeader().AllowAnyMethod();
});
});
var app = builder.Build();
app.UseWatchDogExceptionLogger();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI(opts =>
{
opts.SwaggerEndpoint("/swagger/v1/swagger.json", "v1");
});
}
app.UseHttpsRedirection();
app.MapControllers();
app.MapHealthChecks("/health", new HealthCheckOptions
{
ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse
});
app.MapHealthChecksUI();
app.UseWatchDog(opts =>
{
opts.WatchPageUsername = app.Configuration.GetValue<string>("WatchDog:Username");
opts.WatchPagePassword = app.Configuration.GetValue<string>("WatchDog:Password");
opts.Blacklist = "health";
});
app.UseResponseCaching();
app.UseRouting();
app.UseCors();
app.UseHttpsRedirection();
app.UseAuthentication();
app.UseAuthorization();
app.UseIpRateLimiting();
app.Run();
Login.js
import Button from "react-bootstrap/Button";
import Modal from "react-bootstrap/Modal";
import Form from "react-bootstrap/Form";
import { useState } from "react";
import axios from "axios";
function LoginModal(props) {
const [userName, handleUserName] = useState("");
const [password, handlePassword] = useState("");
async function handleSubmit(e) {
e.preventDefault();
try {
const response = await axios.post(
"https://localhost:7078/api/v1/Authentication/token",
JSON.stringify({ userName, password }),
{
headers: {
"Content-type": "application/json",
},
}
);
console.log(JSON.stringify(response));
} catch (err) {}
}
return (
//Modal
);
}
export default LoginModal;
I must be missing something. Any help is appreciated
Looks like your frontend is working from 'http://localhost:3000' and your backend is 'https://localhost:7078'. Because of different ports these are two different origins, so CORS forbids to access localhost:7078 from localhost:3000 and you need to either disable cors in dev mode, explicitly allow access from localhost:3000 in your backend, something like:
builder.Services.AddCors(options =>
{
options.AddPolicy(name: MyAllowSpecificOrigins,
builder =>
{
builder.WithOrigins("http://localhost:3000");
});
});
Or you can also setup webpack dev server (or whatever you use for development) to proxy requests from localhost:3000 to localhost:7078 and change your frontend, so it will call localhost:3000, but webpack web server will proxy such requests to your backend to localhost:3000 (and in release environment you can do similarly with real web server like nginx or whatever you use)
I was able to figure this out. My application was running in development mode, so I needed to add app.UseCors(); in this if statement within Program.cs:
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI(opts =>
{
opts.SwaggerEndpoint("/swagger/v1/swagger.json", "v1");
});
app.UseCors();
}
I am encountering a weird CORS issue when using C# ASP.NET Core 3.1 and GraphQL (Version="3.3.2"). In the Startup.cs file, I have setup the UseCors like this:
public void Configure(IApplicationBuilder app, ILoggerFactory loggerFactory)
{
if (Environment.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseCors (x => x
.AllowAnyOrigin ()
.AllowAnyMethod ()
.AllowAnyHeader ());
...
}
And also create a ConfigureCors function like this:
private void ConfigureCors(IServiceCollection services)
{
var requestOrigins = Configuration.GetSection("RequestOrigins")?
.GetChildren()
.Select(url => url.Value)
.ToArray() ?? new string[] {};
services.AddCors(options =>
{
options.AddPolicy(name: AllowSpecificOrigins,
builder =>
{
builder.WithOrigins(requestOrigins)
.AllowAnyHeader()
.AllowCredentials()
.AllowAnyMethod();
});
});
}
Called the ConfigureCors like this:
public void ConfigureServices(IServiceCollection services)
{
ConfigureCors(services);
...
}
In appsetting.{env}.json, I set the RequestOrigins:
"RequestOrigins": [
"http://localhost:8889"
]
When using frontend React to call the mutation like this:
const link = new HttpLink({
uri: 'https://localhost:5001/graphql/v1',
fetchOptions: {
credentials: 'include'
},
headers : {Authorization: `Bearer ${localStorage.getItem('Token')}`}
})
export default new ApolloClient({
link,
cache
});
It will throw the CORS issue:
Access to fetch at 'https://localhost:5001/graphql/v1' from origin 'http://localhost:8889' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'.
However the backend log shows:
info: Microsoft.AspNetCore.Hosting.Diagnostics[1]
Request starting HTTP/1.1 OPTIONS https://localhost:5001/graphql/v1
info: Microsoft.AspNetCore.Cors.Infrastructure.CorsService[4]
CORS policy execution successful.
I am very confused:
Why are the OPTIONS not the POST, since I am calling a graphql mutation?
Why backend shows CORS policy execution successful, but frontend got CORS blocker?
However, if I commented out the Authentication part like this:
const link = new HttpLink({
uri: 'https://localhost:5001/graphql/v1',
//fetchOptions: {
//credentials: 'include'
//},
//headers : {Authorization: `Bearer ${localStorage.getItem('Token')}`}
})
Got the authorization failed error, but not CORS blocker. The token I have validated work in Postman. If I remove the app.UseCors, the CORS blocker comes back which is understandable. My guess is some CORS related configuration I didn't do right, but not sure which part, anyone knows what's going on? Thanks a lot!
based on Microsoft Doc's in this link when ever u add new policy u need to specify that policy to app.UseCors().
and also pay attention to this
The call to UseCors must be placed after UseRouting, but before UseAuthorization. For more information, see Middleware order.
I have a ASP.NET Core Server running on local IP https://192.168.188.31:44302 with Web API Enpoints.
I can connect to said server with VS Code REST Client.
Now I want to conenct to the Web API with Blazor WebAssembly running on https://192.168.188.31:5555.
My Blozor Code:
#page "/login"
#inject HttpClient Http
[ ... some "HTML"-Code ... ]
#code {
private async Task Authenticate()
{
var loginModel = new LoginModel
{
Mail = "some#mail.com",
Password = "s3cr3T"
};
var requestMessage = new HttpRequestMessage()
{
Method = new HttpMethod("POST"),
RequestUri = ClientB.Classes.Uris.AuthenticateUser(),
Content =
JsonContent.Create(loginModel)
};
var response = await Http.SendAsync(requestMessage);
var responseStatusCode = response.StatusCode;
var responseBody = await response.Content.ReadAsStringAsync();
Console.WriteLine("responseBody: " + responseBody);
}
public async void LoginSubmit(EditContext editContext)
{
await Authenticate();
Console.WriteLine("Debug: Valid Submit");
}
}
When I now trigger LoginSubmit I get the following error-message in the developer console of Chrome and Firefox: login:1 Access to fetch at 'https://192.168.188.31:44302/user/authenticate' from origin 'https://192.168.188.31:5555' 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.
I'm new to web development and found that you have to enable CORS on the server-side ASP.NET Core project, so I extended startup.cs with
readonly string MyAllowSpecificOrigins = "_myAllowSpecificOrigins";
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<UserDataContext, UserSqliteDataContext>();
services.AddCors(options =>
{
options.AddPolicy(name: MyAllowSpecificOrigins,
builder =>
{
builder.WithOrigins("https://192.168.188.31:44302",
"https://192.168.188.31:5555",
"https://localhost:44302",
"https://localhost:5555")
.AllowAnyHeader()
.AllowAnyMethod();
});
});
services.AddControllers();
services.AddApiVersioning(x =>
{
...
});
services.AddAuthentication(x =>
...
});
services.AddAutoMapper(AppDomain.CurrentDomain.GetAssemblies());
services.AddScoped<IViewerService, ViewerService>();
}
public void Configure(IApplicationBuilder app,
IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
Program.IsDevelopment = env.IsDevelopment();
app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseCors(MyAllowSpecificOrigins);
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
Log.Initialize();
}
But I still get above error message.
Am I doing something wrong with configuring CORS?
Why is it working as expected with the VS Code REST Client and how am I making the call wrong in the Blazor WASM application?
The issue causing the error message login:1 Access to fetch at 'https://192.168.188.31:44302/user/authenticate' from origin 'https://192.168.188.31:5555' 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. was caused by HttpsRedirection.
To resolve the issue, either deactivate HttpsRedirection by removing the line app.UseHttpsRedirection(); in function Configure or add the proper ports for redirection in function ConfigureServices (recommended way).
In my case, I start my WebAPI at port 44302, so my solution looks like this (you have to adapt it to your port number):
if (Program.IsDevelopment)
{
services.AddHttpsRedirection(options =>
{
options.RedirectStatusCode = StatusCodes.Status308PermanentRedirect;
options.HttpsPort = 44302;
});
}
else
{
services.AddHttpsRedirection(options =>
{
options.RedirectStatusCode = StatusCodes.Status308PermanentRedirect;
options.HttpsPort = 443;
});
}
Also note that it is sufficient to add the IP address of the requesting API to CORS like this:
services.AddCors(options =>
{
options.AddPolicy(name: specificOrigins,
builder =>
{
builder.WithOrigins("https://192.168.188.31:5555",
"http://192.168.188.31:5444")
.AllowAnyHeader()
.AllowAnyMethod();
});
});
Step 1: Please add following code in your WebAPI's Startup.cs to allow CORS with specific origins:
services.AddCors(options =>
{
options.AddDefaultPolicy(builder =>
builder.WithOrigins("https://localhost:44351")
.AllowAnyHeader()
.AllowAnyMethod());
});
Step 2: Now change "https://localhost:44351" in above code with your blazor web assembly application's URL. Refer below screen shot:
Step 3: Now add app.UseCors() in your WebAPI's Configure method after app.UseRouting() and before app.UseRouting(). Please refer below screen shot:
I was also facing same issue and it solved my problem. Hope it will also work for you.
Note: No changes required in Blazor web assembly code to fix the above issue.
Been attempting to integrate a React front-end with a .NET Framework backend and I am constantly coming into contact with CORS errors. The request I am sending to the server works on Postman. I extracted the code from Postman and put it into my react app (Fetch) and I receive the following error:
Access to fetch at 'http://localhost:33333/Token' from origin 'http://localhost:3000' has been blocked by CORS policy: 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.
However, on my .NET backend I added the following filter:
using System;
using System.Web.Mvc;
namespace TheFifth.Cors
{
public class AllowCrossSiteAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
filterContext.RequestContext.HttpContext.Response.AddHeader("Access-Control-Allow-Origin",
"*");
filterContext.RequestContext.HttpContext.Response.AddHeader("Access-Control-Allow-Headers",
"*");
filterContext.RequestContext.HttpContext.Response.AddHeader("Access-Control-Allow-Credentials",
"true");
base.OnActionExecuting(filterContext);
}
}
}
Then referenced the Filter at the top of my Controller
[AllowCrossSite]
public class DA_Object
{
//some code
}
Does anyone know why my .NET backend or my React Frontend is preventing me from communicating across different ports - even though it works on Postman?
Additional Details
var myHeaders = new Headers();
myHeaders.append("Content-Type", "application/x-www-form-urlencoded");
var urlencoded = new URLSearchParams();
urlencoded.append("type", "x");
urlencoded.append("username", "x#x.com");
urlencoded.append("password", "x#");
var requestOptions = {
method: 'POST',
headers: myHeaders,
body: urlencoded,
redirect: 'follow'
};
fetch("http://localhost:33333/api/Token", requestOptions)
.then(response => response.text())
.then(result => console.log(result))
.catch(error => console.log('error', error));
In your startup.cs
in the ConfigureServices method you should have something like this, if you don't have then add it:
services.AddCors(options =>
{
options.AddPolicy(DefaultCorsPolicyName, builder =>
{
//App:CorsOrigins in appsettings.json can contain more than one address with splitted by comma.
builder
.AllowAnyOrigin()
.SetIsOriginAllowedToAllowWildcardSubdomains()
.AllowAnyHeader()
.AllowAnyMethod();
});
});
And in your appsettings.json add http://0.0.0.0:80 like this:
"App": {
...
"CorsOrigins": "http://*.mycompany.com,http://0.0.0.0:80",
...}
Another solution is to add a CORS extention in your browser and enable it, but it's not recommended
My application is working fine in IE browser, But it's not working in Chrome browser due to CORS issue.
The issue is
Failed to load http://localhost:52487/api/Authentication/: The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'. Origin 'http://localhost:4200' is therefore not allowed access. The credentials mode of requests initiated by the XMLHttpRequest is controlled by the withCredentials attribute.
I am using angular 2 in front-end and using Asp.net core 1.0 in back-end. I have tried
This is my startup code
public void ConfigureServices(IServiceCollection services)
{
services.AddCors(options =>
{
options.AddPolicy("AllowAll", p =>
{
p.AllowAnyOrigin()
.AllowAnyHeader()
.AllowAnyMethod();
});
});
// Add framework services.
services.AddMvc();
// Add functionality to inject IOptions<T>
services.AddOptions();
// Add our Config object so it can be injected
services.Configure<Data>(Configuration.GetSection("Data"));
services.Configure<COCSettings>(Configuration.GetSection("COCSettings"));
services.Configure<EmailSettings>(Configuration.GetSection("EmailSettings"));
AppSettings.ConnectionString = Configuration["Data:DefaultConnectionString"];
// *If* you need access to generic IConfiguration this is **required**
services.AddSingleton<IConfiguration>(Configuration);
// Injecting repopsitories with interface
AddServices(services);
// Add Json options
services.AddMvc().AddJsonOptions(options => options.SerializerSettings.ContractResolver = new DefaultContractResolver());
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
loggerFactory.AddConsole(Configuration.GetSection("Logging"));
loggerFactory.AddDebug();
app.UseMiddleware(typeof(ErrorHandling));
app.UseMiddleware(typeof(GetNoCache));
app.UseCors("AllowAll");
app.UseMvc();
}
this is how I am calling the API from UI(angular) side
constructor(private http: Http) {
this.headers = new Headers();
this.headers.append('Accept', 'application/json');
}
GetMaintainCOC(FYONId) {
return this.http.get(this.apiUrl + 'GetCertificationofConformity?FYONId=' + FYONId, { withCredentials: true })
.map(responce => <any>responce.json())
.catch(error => {
return Observable.throw(error);
});
}
It is working, when I am calling AllowCredentials() inside of AddPolicy
services.AddCors(options =>
{
options.AddPolicy("AllowAll", p =>
{
p.AllowAnyOrigin()
.AllowAnyHeader()
.AllowAnyMethod()
.AllowCredentials();
});
});
I got this key of idea from
Access-Control-Allow-Origin: "*" not allowed when credentials flag is true, but there is no Access-Control-Allow-Credentials header
What I understood
I am using { withCredentials: true } in angular http service call. So I guess I should use AllowCredentials() policy in CORS service.
Well you appear to have it solved, but here's the simple answer.
If you set the withCredentials flag in the request definition, cookies etc. will be passed in the request. Otherwise they won't be passed.
If your server returns any Set-Cookie response headers, then you must also return the Access-Control-Allow-Credentials: true response header, otherwise the cookies will not be created on the client. And if you're doing that, you need to also specify the EXACT origin in the Access-Control-Allow-Origin response header, since Access-Control-Allow-Origin: * is not compatible with credentials.
So do this:
Pass withCredentials in request
Pass Access-Control-Allow-Origin: <value-of-Origin-request-header> response header
Pass Access-Control-Allow-Credentials: true response header