The 'Access-Control-Allow-Origin' header contains multiple values ' ', '*' - asp.net-web-api

I am working with ASP.NET WEB Api, and I'm using authentication Token, Internet Explorer generates the Token string:
But using any other browser shows the following error :
The 'Access-Control-Allow-Origin' header contains multiple values
AJAX code:
function ObtenerToken(user, password) {
var data = { username: user, password: password, grant_type: "password" }
$.ajax({
url: 'http://localhost:50196/Token',
method: "post",
data: data,
contentType: "application/json",
error: function (e) {
alert('Hubo un error al intentar autenticar al usuario.');
console.log(e);
},
success: function (response) {
var token = response.access_token;
alert(token);
}
});
}
The file Startup.Auth.cs i have set the following
app.UseCors(CorsOptions.AllowAll);
In WebApiConfig.cs
EnableCorsAttribute cors = new EnableCorsAttribute("*", "*", "*");
config.EnableCors(cors);
And in class Controller:
[EnableCors(origins: "*", headers: "*", methods: "*")]
public class UsuariosController : ApiController
{

I'm pretty sure this is because you're adding the Access-Control-Allow-Origin header in all three of those places. You should enable CORS in Startup.Auth.cs, in WebApiConfig.cs, OR in the controller - one of these places, not all three.

You need to enable cors.
public void Configuration(IAppBuilder app)
{
HttpConfiguration config = new HttpConfiguration();
app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);
ConfigureOAuth(app);
WebApiConfig.Register(config);
// Make sure this line is called before ConfigureAuth(app),
// app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);
app.UseWebApi(config);
}

Related

Rest API - 405 method not allowed [duplicate]

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

REST Service, access not allowed on POST

I created a REST service and I'm connecting to it using JQuery ajax and I'm passing and receiving data as JSON. When I'm using GET it works fine but when I'm doing a POST it's not working, It's not even entering debug(service).
It's giving me this error:
XMLHttpRequest cannot load http://localhost:23262/GetAllDrawsShort. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:40464' is therefore not allowed access.
and I'm using the Access-Control-Allow-Origin: * which should allow all domains
I found similar issues and tried them but didn't work for me.
Code in Global.asax (Service):
private void EnableCrossDmainAjaxCall()
{
HttpContext.Current.Response.AddHeader("Access-Control-Allow-Origin", "*");
if (HttpContext.Current.Request.HttpMethod == "OPTIONS")
{
HttpContext.Current.Response.AddHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS");
HttpContext.Current.Response.AddHeader("Access-Control-Allow-Headers", "Content-Type, Accept");
HttpContext.Current.Response.AddHeader("Access-Control-Max-Age", "1728000");
HttpContext.Current.Response.End();
}
}
Service class (Service):
[OperationContract]
[WebInvoke(Method = "POST", UriTemplate = "GetAllDrawsShort", BodyStyle = WebMessageBodyStyle.WrappedRequest, ResponseFormat = WebMessageFormat.Json)]
public List<DrawShortObject> GetAllDrawsShort(string token, Guid userId)
{
if (Util.IsAuth(token))
{
return new DrawLogic().GetAllDrawsShort(userId);
}
else return null;
}
JQuery (Client page):
function GetAllDrawsShort() {
var jData = {};
jData.token = "123";
jData.userId = "2f9e15d9-3654-4a43-89f4-07fea98a146f";
return $.ajax({
cache: false,
type: "POST",
async: true,
url: address + "GetAllDrawsShort",
data: JSON.stringify(jData),
contentType: "application/json",
dataType: "json"
});
};
I had a similar issue. I solved the problem using jsonp as dataType and responding with a custom callback wrapped response.
First change your ajax request dataType to 'jsonp'.
Then build your service response:
string callback = HttpContext.Current.Request.QueryString["callback"];
string data = callback + "(" + yourJsonData + ")";
HttpContext.Current.Response.Write(data);

Ajax call from LocalHost to same domain MVC Controller during using KendoDataSource

I am trying to access data from an MVC controller that is on an IIS Server located within my domain. I'm getting this error
"No 'Access-Control-Allow-Origin' header is present on the requested resource.
Origin 'http://localhost:22205' is therefore not allowed access. "
Here is my ajax call:
binDropDownDataSource: new kendo.data.DataSource({
autobind: false,
serverFiltering: true,
dataType: "json",
crossDomain: true,
transport: {
read: {
cache: false,
//url: "/LogisticsWebApp/Requisitions/GetBins", This works if unremarked
url: "https://www.MyDomain.com/LogisticsWebApp/requisitions/getsites",
xhrFields: {
withCredentials: true
},
data: function () {
{
siteCode: viewModel.site.SiteCode,
shopCode: viewModel.binShopBlock.ShopCode
};
}
}
}
})
Here is my controller:
public JsonResult GetBins(string siteCode, string shopCode)
{
var lookups = new Lookups();
var data = lookups.GetBins(siteCode,shopCode);
return Json(data, JsonRequestBehavior.AllowGet);
}
I want to be able to use an application as my data layer but need to be able to develop against it.
If you need it your for this particular method, you might change your GetBins action to:
public JsonResult GetBins(string siteCode, string shopCode)
{
HttpContext.Response.AddHeader("Access-Control-Allow-Origin", "*");
var lookups = new Lookups();
var data = lookups.GetBins(siteCode,shopCode);
return Json(data, JsonRequestBehavior.AllowGet);
}
Edit
If you need to do that from a method that is not in the controller you must use:
HttpContext.Current.Response.AddHeader("Access-Control-Allow-Origin", "*");
Add header ("Access-Control-Allow-Origin","*") as well as header ("Access-Control-Allow-Headers", "X-Requested-With")
System.Web.HttpContext.Current.Response.AddHeader("Access-Control-Allow-Origin", "*");
System.Web.HttpContext.Current.Response.AddHeader("Access-Control-Allow-Headers", "X-Requested-With");

Accessing ServiceStack Authenticated Service using Ajax

I've been working through a simple API example, a modified version of the ServiceStack Hello World example with authentication. The goal of the proof of concept is to create an a RESTful API that contains services requiring authentication accessible entirely through Ajax from several different web projects.
I've read the wiki for, and implemented, Authentication and authorization and implementing CORS (many, results [sorry, not enough cred to point to the relevant link]). At this point, my Hello service can authenticate using a custom authentication mechanism which is over-riding CredentialsAuthProvider and a custom user session object. I've created, or borrowed, rather, a simple test application (an entirely separate project to simulate our needs) and can authenticate and then call into the Hello service, passing a name, and receive a 'Hello Fred' response through a single browser session. That is, I can call the /auth/credentials path in the url, passing the username and id, and receive a proper response. I can then update the url to /hello/fred and receive a valid response.
My breakdown in understanding is how to implement the authentication for all ajax calls. My initial login, below, works fine. No matter what I do, my attempt to call the authenticated service via ajax, I either receive a OPTIONS 404 error or Not Found error, or Origin http // localhost:12345 (pseudo-link) is not allowed by Access-Control-Allow-Origin, etc.
Do I need to go this route?
Sorry if this is confusing. I can provide greater details if required, but think this might be sufficient help the knowledgeable to help my lack of understanding.
function InvokeLogin() {
var Basic = new Object();
Basic.UserName = "MyUser";
Basic.password = "MyPass";
$.ajax({
type: "POST",
contentType: "application/json; charset=utf-8",
dataType: "json",
data: JSON.stringify(Basic),
url: "http://localhost:58795/auth/credentials",
success: function (data, textStatus, jqXHR) {
alert('Authenticated! Now you can run Hello Service.');
},
error: function(xhr, textStatus, errorThrown) {
var data = $.parseJSON(xhr.responseText);
if (data === null)
alert(textStatus + " HttpCode:" + xhr.status);
else
alert("ERROR: " + data.ResponseStatus.Message + (data.ResponseStatus.StackTrace ? " \r\n Stack:" + data.ResponseStatus.StackTrace : ""));
}
});
}
EDIT:
Based on the responses and the link provided by Stefan, I've made a couple of changes:
My Config (Note: I'm using custom authentication and session object and that is all working correctly.)
public override void Configure(Funq.Container container)
{
Plugins.Add(new AuthFeature(() => new CustomUserSession(),
new IAuthProvider[] {
new CustomCredentialsAuthProvider(),
}));
base.SetConfig(new EndpointHostConfig
{
GlobalResponseHeaders = {
{ "Access-Control-Allow-Origin", "*" },
{ "Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS" },
{ "Access-Control-Allow-Headers", "Content-Type, Authorization" },
},
DefaultContentType = "application/json"
});
Plugins.Add(new CorsFeature());
this.RequestFilters.Add((httpReq, httpRes, requestDto) =>
{
//Handles Request and closes Responses after emitting global HTTP Headers
if (httpReq.HttpMethod == "OPTIONS")
httpRes.EndRequest(); // extension method
});
Routes
.Add<Hello>("/Hello", "GET, OPTIONS");
container.Register<ICacheClient>(new MemoryCacheClient());
var userRep = new InMemoryAuthRepository();
container.Register<IUserAuthRepository>(userRep);
}
My Simple Hello Service
[EnableCors]
public class HelloService : IService
{
[Authenticate]
public object GET(Hello request)
{
Looks strange when the name is null so we replace with a generic name.
var name = request.Name ?? "John Doe";
return new HelloResponse { Result = "Hello, " + name };
}
}
After making the login call, above, my subsequent call the Hello service is now yielding a 401 error, which is progress, though not where I need to be. (The Jquery.support.cors= true is set in my script file.)
function helloService() {
$.ajax({
type: "GET",
contentType: "application/json",
dataType: "json",
url: "http://localhost:58795/hello",
success: function (data, textStatus, jqXHR) {
alert(data.Result);
},
error: function (xhr, textStatus, errorThrown) {
var data = $.parseJSON(xhr.responseText);
if (data === null)
alert(textStatus + " HttpCode:" + xhr.status);
else
alert("ERROR: " + data.ResponseStatus.Message +
(data.ResponseStatus.StackTrace ? " \r\n Stack:" + data.ResponseStatus.StackTrace : ""));
}
});
}
Again, this works in the RESTConsole if I first make the call to /auth/credentials properly and then follow that up with a call to /hello.
FINAL EDIT
Following Stefan's advise, below, including many other links, I was finally able to get this working. In addition to Stefan's code, I had to make one additional modification:
Plugins.Add(new CorsFeature(allowedHeaders: "Content-Type, Authorization"));
On to the next challenge: Updating Jonas Eriksson's CustomAuthenticateAttibute code (which appears to be using an older version of ServiceStack as a couple of functions are no longer available.
THANKS AGAIN STEFAN!!
this code works for me, based on the Wiki documentation Custom authentication and authorization
Code is based also in the blog post from Community Resources
CORS BasicAuth on ServiceStack with custom authentication
For Basic Authentication, a custom provider
public class myAuthProvider : BasicAuthProvider
{
public myAuthProvider() : base() { }
public override bool TryAuthenticate(IServiceBase authService, string userName, string password)
{
//Add here your custom auth logic (database calls etc)
//Return true if credentials are valid, otherwise false
if (userName == "admin" && password == "test")
return true;
else
return false;
}
public override void OnAuthenticated(IServiceBase authService, IAuthSession session, IOAuthTokens tokens, Dictionary<string, string> authInfo)
{
//Fill the IAuthSession with data which you want to retrieve in the app
// the base AuthUserSession properties e.g
session.FirstName = "It's me";
//...
// derived CustomUserSession properties e.g
if(session is CustomUserSession)
((CustomUserSession) session).MyData = "It's me";
//...
//Important: You need to save the session!
authService.SaveSession(session, SessionExpiry);
}
}
public class CustomUserSession : AuthUserSession
{
public string MyData { get; set; }
}
In AppHost
using System.Web;
using ServiceStack; // v.3.9.60 httpExtensions methods, before in ServiceStack.WebHost.Endpoints.Extensions;
using ....
AppHost.Configure
public override void Configure(Container container)
{
SetConfig(new ServiceStack.WebHost.Endpoints.EndpointHostConfig
{
DefaultContentType = ContentType.Json
..
// remove GlobalResponseHeaders because CordFeature adds the CORS headers to Config.GlobalResponseHeaders
});
Plugins.Add(new CorsFeature(allowedHeaders: "Content-Type, Authorization")); //Registers global CORS Headers
this.RequestFilters.Add((httpReq, httpRes, requestDto) =>
{
if (httpReq.HttpMethod == "OPTIONS")
httpRes.EndRequestWithNoContent(); // v 3.9.60 httpExtensions method before httpRes.EndServiceStackRequest();
});
//Register all Authentication methods you want to enable for this web app.
Plugins.Add(new AuthFeature(() => new CustomUserSession(), // OR the AuthUserSession
new IAuthProvider[] {
new myAuthProvider(),
}) { HtmlRedirect = null }); // Redirect on fail
HtmlRedirect answer
Routes.Add<TestRequest>("/TestAPI/{Id}", "POST,GET, OPTIONS");
....
}
In Service
[Authenticate]
public class TestAPI : Service
{
...
}
in javascript
jQuery.support.cors = true;
function make_base_auth(user, password) {
var tok = user + ':' + password;
var hash = btoa(tok);
return "Basic " + hash;
}
Login first
function Authenticate() {
$.ajax({
type: 'Post',
contentType: 'application/json',
url: serverIP + 'Auth',
cache: false,
async: false,
data: {},
dataType: "json",
beforeSend: function (xhr) {
xhr.setRequestHeader("Authorization", make_base_auth(username, password));
},
success: function (response, status, xhr) {
localStorage.sessionId = data.SessionId;
var UserName = response.userName;
},
error: function (xhr, err) {
alert(err);
}
});
}
and request
function DoTest() {
var TestRequest = new Object();
TestRequest.name = "Harry Potter";
TestRequest.Id = 33;
var username = "admin";
var password = "test";
$.ajax({
type: 'Post',
contentType: 'application/json',
cache: false,
async: false,
url: serverIP + '/TestAPI/'+ TestRequest.Id,
data: JSON.stringify(TestRequest),
dataType: "json",
beforeSend: function (xhr) {
xhr.setRequestHeader("Session-Id", localStorage.sessionId);
},
success: function (response, status, xhr) {
var s= response.message;
},
error: function (xhr, err) {
alert(xhr.statusText);
}
});
}
these questions here and here are helpful.
Also this answer for CredentialsAuthProvider, in case we can use cookies and sessions.

Ajax json post to Controller across domains, "not allowed by" Access-Control-Allow-Headers

I create a simple MVC Controller action, that takes some json data - then return true or false.
[AllowCrossSiteJson]
public JsonResult AddPerson(Person person)
{
//do stuff with person object
return Json(true);
}
I call it from javascript:
function saveData(person) {
var json = $.toJSON(person); //converts person object to json
$.ajax({
url: "http://somedomain.com/Ajax/AddPerson",
type: 'POST',
dataType: 'json',
data: json,
contentType: 'application/json; charset=utf-8',
success: function (data) {
alert("ok");
}
});
}
Everything works as long as I am on the same domain, but as soon as I call it from another domain, I run into problems.
On the controller is an action filter "AllowCrossSiteJson" that sets the header "Access-Control-Allow-Origin" to "*", allowing any origin to access the controller action.
public class AllowCrossSiteJsonAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
filterContext.RequestContext.HttpContext.Response.AddHeader("Access-Control-Allow-Origin", "*");
base.OnActionExecuting(filterContext);
}
}
However - I then get this error in firebug, when calling across domains:
OPTIONS http://somedomain.com/Ajax/AddPerson?packageId=3 500 (Internal Server Error)
XMLHttpRequest cannot load http://somedomain.com/Ajax/AddPerson. Request header field Content-Type is not allowed by Access-Control-Allow-Headers.
What is wrong here?
I have been looking through possible solutions for hours, and it seems to be something to do with jquery using OPTIONS (not POST as I would expect).
If that is indeed the problem, how can I fix that?
To fix the Access-Control-Allow-Origin error, you need to include the following header in your response:
Access-Control-Allow-Headers: Content-Type
Basically, any "non-simple" header needs to be included as a comma-delimited list in the header above. Check out the CORS spec for more details:
http://www.w3.org/TR/cors/
"Content-Type" needs to be included because "application/json" does not match the values defined here:
http://www.w3.org/TR/cors/#terminology
I'd recommend you JSONP, it's the only really cross browser and reliable solution for cross domain AJAX. So you could start by writing a custom action result that will wrap the JSON response with a callback:
public class JsonpResult : ActionResult
{
private readonly object _obj;
public JsonpResult(object obj)
{
_obj = obj;
}
public override void ExecuteResult(ControllerContext context)
{
var serializer = new JavaScriptSerializer();
var callbackname = context.HttpContext.Request["callback"];
var jsonp = string.Format("{0}({1})", callbackname, serializer.Serialize(_obj));
var response = context.HttpContext.Response;
response.ContentType = "application/json";
response.Write(jsonp);
}
}
and then:
public ActionResult AddPerson(Person person)
{
return new JsonpResult(true);
}
and finally perform the cross domain AJAX call:
$.ajax({
url: 'http://somedomain.com/Ajax/AddPerson',
jsonp: 'callback',
dataType: 'jsonp',
data: { firstName: 'john', lastName: 'smith' },
success: function (result) {
alert(result);
}
});

Resources