I know this is a topic that occures a lot. I have searched the Internet but I could not find a solution for my problem yet:
I am developing an SAPUI5 Fiori app in the SAP Web IDE. The App will be deployed on an internal server within our company network. So the app will only work inside the company network.
Now I have simple ASP.NET Core Web API that is running on a separate server also inside the company network.
When i deploy the app and try to consume the web api via AJAX request, i become the following error:
Access to XMLHttpRequest at 'http://myserver:5000/api/test' from
origin 'https://sap.mycompany.com:44315' 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.
My Code on the Web API:
Startup.cs:
public void ConfigureServices(IServiceCollection services)
{
services.AddCors(options =>
{
options.AddPolicy(
"AllowOrigin",
builder => builder.WithOrigins("https://sap.mycompany.com:44315")
.AllowAnyMethod()
.AllowAnyHeader()
.AllowCredentials()
);
});
services.AddAuthentication(IISDefaults.AuthenticationScheme);
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
services.Configure<MvcOptions>(options => options.Filters.Add(new CorsAuthorizationFilterFactory("AllowOrigin")));
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseCors("AllowOrigin");
app.UseMvc();
}
Controller:
// POST: api/test
[HttpPost]
public async Task<IActionResult> test([FromBody] item)
{
try
{
// Do some stuff
}
catch (Exception ex)
{
// throw exception
return BadRequest("Error");
}
return Ok("Success");
}
My Code on the Fiori-Frontend:
Controller:
onTestButtonPress: async function (e) {
$.ajax({
type: "POST",
url: "http://myserver:5000/api/test",
dataType: "json",
crossDomain: true,
data: $.param({
"Firstname":"John",
"Lastname":"Rambo"
}),
success: function (response) {
console.log("Success");
},
error: function (response) {
console.log("Error");
}
});
}
I Have tried anything but I still receive the CORS error in Google Chrome. I also startet Google Chrome with diabled web-security:
chrome.exe --disable-web-security --disable-gpu
Does anyone have any idea what I am missing here?
Thanks a lot
If your SAPUI5 app runs on SAP Cloud Platform, you should define your REST API as a Destination and then consume that destination from your app.
If it runs on SAP Gateway (or any other web server you have control of), you may configure your server to respond with header like ‘Access-Control-Allow-Origin’ : ‘http://myserver:5000/api/test’
Now after a few hours struggling, finally it works. I have changed my code on the API as following:
public void ConfigureServices(IServiceCollection services)
{
services.AddCors(options =>
{
options.AddPolicy(
"AllowOrigin",
builder => builder.WithOrigins("https://sap.mycompany.com:44315")
.AllowAnyMethod()
.AllowAnyHeader()
.AllowCredentials()
);
});
services.AddAuthentication(IISDefaults.AuthenticationScheme);
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
services.Configure<MvcOptions>(options => options.Filters.Add(new CorsAuthorizationFilterFactory("AllowOrigin")));
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseCors("AllowOrigin");
app.UseMvc();
}
Also I have forgot to add the ContentType in my Ajax-Request:
$.ajax({
type: "POST",
url: "http://myserver:5000/api/test",
dataType: "json",
contentType: "application/json",
crossDomain: true,
data: $.param({
"Firstname":"John",
"Lastname":"Rambo"
}),
success: function (response) {
console.log("Success");
},
error: function (response) {
console.log("Error");
}
});
I had the same problem. For me help this --disable-web-security --user-data-dir as parameter for google chrome
Related
The CORS problem it shows:
OPTIONS https://dev-01-api-apptracker2/Admin 401 (Unauthorized)
Access to XMLHttpRequest at 'https://dev-01-api-apptracker2/Admin' from origin 'https://dev-01-web-apptracker2' 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.
But I think I already added a header 'Access-Control-Allow-Origin': '*' in my ajax code, and try many way to solve these CORS problem, I set dataType: 'json', crossDomain: true, and withCredentials: true, and also add different origin domain. But I still get error.
I have no idea what's wrong with this, is anyone can help me. Thanks!!
AddAdmin: function (callback, UserId) {
$.ajax({
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
'Access-Control-Allow-Headers': 'origin, X-Custom-Header',
'Access-Control-Allow-Method': 'POST',
'Access-Control-Allow-Origin': '*'
},
contentType: 'application/json',
method: "POST",
url: Services.APIBaseUrl + "Admin",
dataType: 'json',
crossDomain: true,
data: JSON.stringify(UserId),
xhrFields: {
withCredentials: true
},
complete: function (data) {
callback(data);
}
});
},
public void ConfigureServices(IServiceCollection services)
{
services.AddCors(options =>
{
options.AddPolicy("APIAllowedOriginsPolicy",
builder =>
{
builder.WithOrigins("https://dev-01-web-apptracker2",
"http://localhost:31474")
.AllowAnyHeader()
.AllowAnyMethod()
.AllowCredentials();
});
});
services.Configure<MvcOptions>(options =>
{
options.Filters.Add(new CorsAuthorizationFilterFactory("APIAllowedOriginsPolicy"));
});
services.AddAuthentication(IISDefaults.AuthenticationScheme);
// Add framework services.
services
.AddMvc()
.AddJsonOptions(options =>
{
options.SerializerSettings.ContractResolver = new DefaultContractResolver();
});
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
//app.UseCors("APIAllowedOriginsPolicy");
app.UseCors(builder =>
builder.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader()
.AllowCredentials()
);
app.UseMvc();
}
I figure out the problem that was because IIS Authentication problem, It need to allow both windows auth and anonymous for CORS.
I know this has been asked dozens of times but I'm really frustrated as none of the suggestions I can find out there work for me and I'm really stuck.
My problem is I'm not being able to call a Web Api from ajax, no matter what configurations/combinations/whatever of routes and everything I try, none of them works and I just get 404.
This is my Global.asax file:
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
GlobalConfiguration.Configure(WebApiConfig.Register);
}
This is my WebApiConfig.cs in App_Start folder:
public static void Register(HttpConfiguration config)
{
// Web API configuration and services
// Configure Web API to use only bearer token authentication.
config.SuppressDefaultHostAuthentication();
config.Filters.Add(new HostAuthenticationFilter(OAuthDefaults.AuthenticationType));
// Web API routes
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
This is my UserController class:
public class UserController : ApiController
{
public IHttpActionResult GetUserDataById(string id)
{
Clients jsonData = Http.downloadJsonData<Clients>(InsuranceGlobal.clientsUrl);
Client user = jsonData.clients.Where(u => u.id == id).FirstOrDefault();
return Ok(user);
}
}
This is my Ajax call inside cshtml javascript section:
$("#btnGetUserById").click(function () {
$('#userByName').empty();
$("#gettingByIdMsg").text(" Getting User...");
$.ajax({
url: '../api/User',
type: "GET",
contentType: "application/json",
dataType: "json",
data: { id: $("#userId").val() },
success: function (data) {
$('<tr>', { html: formatItem(data) }).appendTo($('#userByName'));
$("#usersTable").removeClass("hidden");
$("#gettingByIdMsg").text("");
},
fail: function (jqXHR, textStatus) {
$("#gettingByIdMsg").text("Request failed: " + textStatus);
}
});
});
I tried GET as well as POST with the [HttpPost] decorator with no avail.
I guess I have all necessary Web Api NuGet packages installed and the app compiles without errors but web api is not being called.
Please help.
Edit 1:
I have to mention that -on purpose- I haven't started a new project with WebApi template in Visual Studio, instead I started a MVC project and then installed all NuGet WebApi necessary packages and configuration (maybe I missed something, don't know).
Ok, after solving my issue I'll answer my own question.
First of all I have to say thanks for all the replies. Love this community and people is very nice here.
After diving into depths of sea... err my solution configuration and fighting a lot with it I remembered I've previously installed WebApi.Owin package and just to try I decided to uninstall it leaving only AspNet.WebApi and voilá, now the WebApi calls are working.
I hope all this effort will help anyone else having a similar issue in the future.
Change
EDIT: based on comment
[RoutePrefix("api/User")]
public class UserController : ApiController
{
[Route("getbyid/{id}")]
public IHttpActionResult GetUserDataById(string id)
{
Clients jsonData = Http.downloadJsonData<Clients> InsuranceGlobal.clientsUrl);
Client user = jsonData.clients.Where(u => u.id ==
id).FirstOrDefault();
return Ok(user);
}
}
and client to
$("#btnGetUserById").click(function () {
$('#userByName').empty();
$("#gettingByIdMsg").text(" Getting User...");
$.ajax({
url: '/api/User/getbyid/' + id: $("#userId").val(),
type: "GET",
success: function (data) {
$('<tr>', { html: formatItem(data) }).appendTo($('#userByName'));
$("#usersTable").removeClass("hidden");
$("#gettingByIdMsg").text("");
},
fail: function (jqXHR, textStatus) {
$("#gettingByIdMsg").text("Request failed: " + textStatus);
}
});
});
I'm developing an netcore MVC application which uses Ajax requests to POST data to the server. I am using IdentityServer4 as my auth middleware. The flow is when the application is launched with a URL of http://localhost:6002 it redirect to IdentityServer (localhost:6000). The user logs in and is redirected to the main application which then works fine.
Ajax GET requests also work correctly. I can observe a list of claims on the Get action in the controller (User.Identity.Claims). However when I try a POST data from the server the request returns a 200 but from the Identity Server with Redirect=true
My call from the Javascript
applyUpdate(modelData) {
let that = this;
fetch("http://localhost:6002/Client/Update/", {
method: 'post',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify(modelData)
}
).then(function (response) {
return response;
}).then(function (outData) {
alert("saved");
});
}
The response I receive is
{type: "cors",
url: "http://localhost:6000/account/login?returnUrl=%2Fc…%26x-client..,
redirected: true,
status: 200,
ok: true}
I have enabled CORS on the applications as previously I was getting 405 issues. What appears to be happening is when I call my controller action from Javascript a redirect is being performed to IdentityServer which is then returning to the client without ever actually executing my action.
My controller action looks like
[Authorize]
[HttpPost]
public async Task<JsonResult> Update([FromBody] MyVM myVM)
{
}
If I remove the [Authorize] attribute the method is reached however the value of User.Identity.Claims is always empty where in a HTTP Get it contains a list of all my claims.
Below is the relevant section for configuring IdentityServer from the Startup.cs file
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();
services.AddAuthentication(options =>
{
options.DefaultScheme = "Cookies";
options.DefaultChallengeScheme = "oidc";
})
.AddCookie("Cookies")
.AddOpenIdConnect("oidc", options =>
{
options.SignInScheme = "Cookies";
options.Authority = identityUrl;
options.RequireHttpsMetadata = false;
options.TokenValidationParameters = new TokenValidationParameters
{
NameClaimType = "name",
RoleClaimType = "role",
};
options.ClientId = "my client";
options.ClientSecret = "secret";
options.ResponseType = "code id_token";
options.SaveTokens = true;
options.GetClaimsFromUserInfoEndpoint = true;
options.UseTokenLifetime = false;
});
I am absolutely stumped at this behavior, any help would be greatly appreciated
UPDATE
Bizarrely I am using the Javascript Fetch API to do the POST, when I swap it out of use Jquery Ajax it works perfectly so many it's the Fetch API that isn't managing the Redirect. This call works fine
$.ajax({
type: "POST",
contentType: "application/json",
dataType: "json",
url: 'http://localhost:6002/Client/Update/',
data: JSON.stringify(modelData),
success: function success(msg) {
alert("saved");
},
error: function error(xhr, data, err) {
console.log(xhr);
}
});
I didn't want to have to include a dependency Jquery
This question already has answers here:
Why am I getting an OPTIONS request instead of a GET request?
(10 answers)
Closed 6 years ago.
I am new to the Rest API. I am trying to call cross domain rest API from my application.
Here is my code -
$.ajax({
type: "GET",
async: false,
url: 'http://xx.xxx.xxx.xx:9003/GetProjectList',
contentType: "application/json",
dataType: "json",
traditional: true,
CrossDomain: true,
data: {
StartDate: '2016-12-20',
EndDate: '2017-01-10'
},
success: function (data) {
alert("Success");
alert(data);
},
error: function (xhr, textStatus, errorThrown) {
alert("Failed");
alert(xhr);
alert(textStatus);
alert(errorThrown);
}
});
But i am getting the error as
OPTIONS http://xx.xxx.xxx.xx:9003/GetProjectList?StartDate=2016-12-20&EndDate=2017-01-10 405 (Method Not Allowed)
XMLHttpRequest cannot load http://xx.xxx.xxx.xx:9003/GetProjectList?StartDate=2016-12-20&EndDate=2017-01-10. 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:64207' is therefore not allowed access. The response had HTTP status code 405.
Am i missing anything here? any code or configuration?
If i hit that URL directly from browser or Postman, its working fine. But its not working from the application.
The problem is about CORS(Cross-Origin Requests). You have to enable CORS for solve the problem.
Download with Nuget Package
Install-Package Microsoft.AspNet.WebApi.Cors
You should add some code in WebApiConfig.cs
var corsAttr = new EnableCorsAttribute("*", "*", "*");
config.EnableCors(corsAttr);
More Information you should take a look:
https://www.asp.net/web-api/overview/security/enabling-cross-origin-requests-in-web-api
I think the problem is a CORS problem (sometimes 405 also mean you're calling your API with wrong HTTP Verbs) .. but reading your exception it looks like a CORS problem .. try this:
using Goocity.API;
using Microsoft.Owin;
using Microsoft.Owin.Cors;
using Owin;
[assembly: OwinStartup("API", typeof(Goocity.API.Startup))]
namespace Goocity.API
{
public partial class Startup
{
public void Configuration(IAppBuilder app)
{
#region TO UNCOMMENT WHEN IS IN PRODUCTION
//var corsPolicy = new CorsPolicy
//{
// AllowAnyMethod = true,
// AllowAnyHeader = true,
// SupportsCredentials = true,
// Origins = { "http://www.yoursite.it" }
//};
//app.UseCors(new CorsOptions
//{
// PolicyProvider = new CorsPolicyProvider
// {
// PolicyResolver = context => Task.FromResult(corsPolicy)
// }
//});
#endregion TO UNCOMMENT WHEN IS IN PRODUCTION
app.UseCors(CorsOptions.AllowAll);
ConfigureAuth(app);
}
}
}
Try to put this in your startUp file and install the Microsoft.Owin.Cors nuget package
Setup:
So I have two visual studio instances running.
1) Backend: MVC 6 Application with a MVC controller called homeController
2) Frontend: Website project. HTML.
I didn't build it with the traditional Views in mvc, but a standalone HTML webpage, using the MVC backend for data. - I like having them separate.
Test:
So I wanted to use sessions for the first time in MVC 6 and followed this guide.
First tests went fine, as I didn't bother to write the html and ajax, I just called the mvc from the address bar like this:
http://localhost:55043/home/setsession
The code behind it is:
[HttpGet]
public string SetSession()
{
string sessionId = "1";
HttpContext.Session.SetString(sessionId, "myvalue");
return sessionId;
}
And then:
http://localhost:55043/home/getsession?sessionId=1
The code behind it is:
[HttpGet]
public string GetSession(string sessionId)
{
string value = HttpContext.Session.GetString(sessionId);
return "session value is: " + value;
}
It gave my value back correctly.
Problem:
But when I wrote the website and its calles the same methods, then its not remembering the value set in the second call.
My code is like this:
$.ajax({
url: url + "/home/SetSession",
type: 'GET',
async: true,
crossDomain: true,
cache: true,
success: function (data) {
alert("finito - Sessionid: " + data);
$.ajax({
url: url + "/home/GetSession",
data: {
sessionId: data,
},
type: 'GET',
async: true,
crossDomain: true,
cache: true,
success: function (data) {
alert(data);
},
error: function (x, t, m) {
alert("failed");
}
});
},
error: function (x, t, m) {
alert("failed);
}
});
So why is it not working for my website? What is the difference?
Some of my Startup.cs:
public void ConfigureServices(IServiceCollection services)
{
// Add framework services.
services.AddMvc();
services.AddCors();
services.AddCaching();
services.AddSession(options => {
options.IdleTimeout = TimeSpan.FromMinutes(30);
options.CookieName = ".BrunataBooking";
});
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
loggerFactory.AddConsole(Configuration.GetSection("Logging"));
loggerFactory.AddDebug();
app.UseIISPlatformHandler();
app.UseStaticFiles();
app.UseSession();
app.UseCors(builder =>
{
builder.WithOrigins("*")
.WithMethods("GET", "POST")
.AllowAnyHeader();
});
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Start}/{id?}");
});
}