webapi 2.0 cross origin behaviour - c#

i am using default webapi ApplicationOAuthProvider code below to login. and i add in
<add name="Access-Control-Allow-Origin" value="*" />
in the web.config and client is able to login via www.testapi.com/token.
everything works fine.
But when i create a custom webapi function. it is still asking me for access-origin control to enable. So i do so by adding this line of code in WebapiConfig.cs
EnableCorsAttribute cors = new EnableCorsAttribute("http://www.myweb.com:82", "*", "*");
config.EnableCors(cors);
this time it prompt error saying
''Access-Control-Allow-Origin' header contains multiple values 'http://www.myweb.com:82, *', but only one is allowed. Origin 'http://www.myweb.com:82' is therefore not allowed access.
so i remove the <add name="Access-Control-Allow-Origin" value="*" /> in the web.config and it works!!.
i return to the login and it is asking for <add name="Access-Control-Allow-Origin" value="*" /> to be added. but if i add this in. my webapi method will not be able to call.
if i dont add. client will not be able to log in.
is there a way for both to work?
below is the response of 200 with error.
Update 1
startup.auth.cs
public void ConfigureAuth(IAppBuilder app)
{
// Configure the db context and user manager to use a single instance per request
app.CreatePerOwinContext(ApplicationDbContext.Create);
app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
// Enable the application to use a cookie to store information for the signed in user
// and to use a cookie to temporarily store information about a user logging in with a third party login provider
app.UseCookieAuthentication(new CookieAuthenticationOptions());
app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);
// Configure the application for OAuth based flow
PublicClientId = "self";
OAuthOptions = new OAuthAuthorizationServerOptions
{
TokenEndpointPath = new PathString("/Token"),
Provider = new ApplicationOAuthProvider(PublicClientId),
AuthorizeEndpointPath = new PathString("/api/Account/ExternalLogin"),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(14),
// In production mode set AllowInsecureHttp = false
AllowInsecureHttp = true
};
// Enable the application to use bearer tokens to authenticate users
app.UseOAuthBearerTokens(OAuthOptions);
app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);//as instructed
webapiconfig.cs
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 }
);
WebApiConfig.Register(config);
config.EnableCors(new EnableCorsAttribute("*", "*", "GET, POST, OPTIONS, PUT, DELETE"));
//var jsonp = new JsonpMediaTypeFormatter(config.Formatters.JsonFormatter);
//config.Formatters.Insert(0, jsonp);
}
}

Install Microsoft.AspNet.WebApi.Cors nuget package
Install Microsoft.Owin.Cors nuget package
Add config.EnableCors(new EnableCorsAttribute("*", "*", "GET, POST, OPTIONS, PUT, DELETE")); to the above of WebApiConfig.Register(config); line at Startup.cs file.
Add app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll); to the Startup.Auth.cs file. This must be done prior to calling IAppBuilder.UseWebApi

ok finally i managed to get it work with help from "#manprit Singh Sahota"
i remove all the access policy from web.config.
and also the line below in WebApiConfig
EnableCorsAttribute cors = new EnableCorsAttribute("*", "*", "*");
config.EnableCors(cors);
i only add this line to the Startup.Auth.cs
public void ConfigureAuth(IAppBuilder app)
{
app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);//working line

Related

Web API slow performance

I am working on Web API project under .NET Framework 4.6 currently.
It uses bearer token authentication.
But I have noticed the issue with response time of controllers' actions. The response time is quite big even Web API is hosted on local IIS Express. Namely the logging (based on IActionFilter) shows the execution time of the controller is 20 milliseconds, meanwhile Postman shows the response time is about 3 or 4 seconds.
What can be the reason of such difference?
Two steps were taken:
to use the extension method SuppressDefaultHostAuthentication in order to avoid possible side effect from a default authentication. No improvements unfortunately.
to add the dependency injection the default implementation of interfaces which were missing initially and respective exceptions were thrown on Web API start. Namely I have added
.RegisterType<IHttpControllerSelector, DefaultHttpControllerSelector>()
.RegisterType<IHttpActionSelector, ApiControllerActionSelector>(). No improvements unfortunately.
Please find below the content of WebApiConfig.cs and Startup.cs files
WebApiConfig.cs
public static void Register(HttpConfiguration config)
{
// Web API configuration and services
config.MapHttpAttributeRoutes();
//config.SuppressDefaultHostAuthentication();
// TODO: check the necessity to use Storages here, why not on services level
var container = new UnityContainer();
/*some dependecies mapping here*/
container.AddExtension(new Diagnostic());
config.DependencyResolver = new UnityResolver(container);
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
config.Filters.Add(new ApiAuthenticationFilter(container.Resolve<BLI.IUserSessionManagement>()));
config.Filters.Add(new ApiAuthorizationFilter(container.Resolve<BLI.IAuthorizer>(), container.Resolve<BET.IAuthLogger>()));
config.Filters.Add(new LoggingFilterAttribute(new BET.ControllerTracer()));
}
Startup.cs file
public void Configuration(IAppBuilder app)
{
//TODO : try to find better solution
BackEnd.WebAPI.Models.UnityResolver ur = (BackEnd.WebAPI.Models.UnityResolver)System.Web.Http.GlobalConfiguration.Configuration.DependencyResolver;
Type providerType = Type.GetType("Microsoft.Owin.Security.OAuth.IOAuthAuthorizationServerProvider, Microsoft.Owin.Security.OAuth", true);
ApiOAuthAuthorizationServerProvider serverProvider = (ApiOAuthAuthorizationServerProvider)ur.GetService(providerType);
//
OAuthAuthorizationServerOptions oAuthOptions = new OAuthAuthorizationServerOptions()
{
TokenEndpointPath = new PathString("/auth"),
Provider = serverProvider,
AccessTokenExpireTimeSpan = TimeSpan.FromMinutes(30),
AllowInsecureHttp = true
};
app.UseOAuthAuthorizationServer(oAuthOptions);
app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions());
}
additionally taken actions:
disable authentication and authorization filters. No improvement detected.
perform the same tests on Azure. The same situation: logging based on action filter reports high performance of contoller actions, but client receives responses with essential delay as on local IIS Express
The reason was found.
It was due to too complex controller constructor.
The revision has solved the issue

CORS enabled but access still denied

For reference I'm using Visual Studio 2017 and Windows 10.
I have an MVC webapi project designed using a template provided by Visual Studio with accounts that are stored in an SQL database. I have another project which is the website itself that the users log into. I'm attempting to debug in VS but am being met with an access is denied error message whenever a GET request is made outside of the initial login. I've enabled CORS on the webapi but it didn't seem to make much of a difference.
Here's how I enabled CORS.
In the WebAPIConfig file I have the following:
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
config.EnableCors();
// 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 }
);
}
}
And then in the Web.config file I have this:
<httpProtocol>
<customHeaders>
<add name="Access-Control-Allow-Origin" value="*" />
<add name="Access-Control-Allow-Headers" value="Content-Type" />
<add name="Access-Control-Allow-Methods" value="GET,POST,PUT,DELETE,OPTIONS" />
<add name="Access-Control-Allow-Credentials" value="true" />
</customHeaders>
</httpProtocol>
This is the code from the website making the call:
function getProfilePicture(username){
var returnValue = [];
jQuery.support.cors = true;
if (window.XMLHttpRequest) {
var xmlhttp = new XMLHttpRequest();
xmlhttp.open("GET", 'http://localhost:60690/api/ProfilePicture?Username=' + username, false);
xmlhttp.setRequestHeader('Content-Type', 'application/json; charset=utf-8');
xmlhttp.setRequestHeader('Authorization', 'Bearer ' + localStorage.getItem('accessToken'));
xmlhttp.send();
if (xmlhttp.status == 200) {
returnValue = jQuery.parseJSON(xmlhttp.responseText);
}
}
return returnValue;
}
The error message says "SCRIPT7002: XMLHttpRequest: Network Error 0x80070005, Access is denied."
Did I not properly enable CORS?
Update
I downloaded Postman in an attempt to figure out the issue. I'm actually able to make GET calls with Postman without any errors. It's returning the data and everything. One thing I did notice is it doesn't look like the Authorization header is actually being sent. It's missing from the data in Fiddler.
Specifying Access-Control-Allow-Credentials: true as a response header is incompatible with Access-Control-Allow-Origin: *. If you're going to use credentials, you must use Access-Control-Allow-Origin: <value-of-origin-request-header>.

Multiple Access-Control-Allow-Origin headers

For reference I'm using Visual Studio 2017 and Windows 10.
I have a web api and corresponding web application with user accounts. When I attempted to login I was met with an error which said No Access-Control-Allow-Origin header is present. I found a guide that walked me through how to setup CORS. This is the guide I used.
https://social.technet.microsoft.com/wiki/contents/articles/33771.fix-to-no-access-control-allow-origin-header-is-present-or-working-with-cross-origin-request-in-asp-net-web-api.aspx
In my WebApiConfig file I have this code
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 }
);
var cors = new EnableCorsAttribute("*", "*", "*");
config.EnableCors(cors);
}
In my AccountController file I added in the EnableCors at the top.
[EnableCors(origins: "*", headers: "*", methods: "*")]
[Authorize]
[RoutePrefix("api/Account")]
Finally, in my Web.config file I added the following:
<httpProtocol>
<customHeaders>
<add name="Access-Control-Allow-Origin" value="*" />
<add name="Access-Control-Allow-Headers" value="Content-Type" />
<add name="Access-Control-Allow-Methods" value="GET,POST,PUT,DELETE,OPTIONS" />
<add name="Access-Control-Allow-Credentials" value="true" />
</customHeaders>
</httpProtocol>
This fixed my login issue however, none of my GETS are working. Here is an example of a GET function:
jQuery.support.cors = true;
if (window.XMLHttpRequest) {
var xmlhttp = new XMLHttpRequest();
xmlhttp.open("GET", 'http://localhost:60690/api/ProfilePicture?Username=' + username, false);
xmlhttp.setRequestHeader('Content-Type', 'application/json; charset=utf-8');
xmlhttp.setRequestHeader('Authorization', 'Bearer ' + localStorage.getItem('accessToken'));
xmlhttp.send();
if (xmlhttp.status == 200) {
returnValue = jQuery.parseJSON(xmlhttp.responseText);
}
}
The GET is throwing an error which says "Multiple Access-Control-Allow-Origin headers are not allowed for CORS response". I don't see where I have multiple Access-Control-Allow-Origin headers anywhere. Where should I be looking?
Update 1
Found something interesting. I used Fiddler to watch everything going on in the background and on the GET function that causes the error I'm seeing this in the headers:
So the "Access-Control-Allow-Origin: *" is definitely showing twice but the question is why. I searched all of my code and I only have that declared once. If I remove that line, it breaks the login page so I have to leave it in.
I think I figured this out. I went into the WebApiConfig file and changed the part about CORS to this:
//var cors = new EnableCorsAttribute("*", "*", "*");
//config.EnableCors(cors);
config.EnableCors();
Then I removed the EnableCors part from my Controller and it sort of started working again. I'm still getting an error on the GET call but I went from two errors to just one so it's progress I guess.

Using Owin authentication; not redirected to LoginPath

Ran into a frustrating problem with ASP.NET Identity. The app does not redirect to the LoginPath, but instead serves a 401.
I've added the AuthorizeAttribute filter to my filters and the AllowAnonymous attribute to the Login action.
I have refactored Configuration() method in Startup.cs to:
public void Configuration(IAppBuilder app)
{
ConfigureAuth(app);
}
public void ConfigureAuth(IAppBuilder app)
{
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = "ApplicationCookie",
LoginPath = new PathString("/user/login")
});
}
as per this question:
MVC 5 Redirect to Login Page Not Working with OWIN
I have edited the web.config file, and added the lines:
<system.webServer>
<modules>
<remove name="FormsAuthentication" />
</system.webServer>
as per this question: ASP.NET MVC 5 Web.config: "FormsAuthenticationModule" or "FormsAuthentication"
I still don't get redirects. On the other side, I have no clue what these fine gentlemen are talking about: https://github.com/aspnet/Security/issues/607
Apparently this line should be solving my problem:
app.UseCookieAuthentication(options => {
options.AutomaticAuthenticate = true;
options.AutomaticChallenge = true;
options.LoginPath = "/Account/Login";
});
The package that contains UseCookieAuthentication override that accepts lambdas or the AutomaticAuthenticate and AutomaticChallenge options is, I assume, Microsof.AspNet.Authentication and Microsof.AspNet.Authentication.Cookies, but both are missing from NuGet.
The web.config contains the owin key: <add key="owin:AppStartup" value="SmartKG.App_Start.Startup" />
EDIT: One peculiar thing I did not mention: Before I've added the UserController, which contains the Login action, I was getting redirected to the proper route, but was getting the missing resource error of course. Once I've added the controller and the action, problems with redirecting started to happen.

How to implement "Access-Control-Allow-Origin" header in asp.net

Is it possible to implement "Access-Control-Allow-Origin" header in asp.net
From enable-cors.org:
CORS on ASP.NET
If you don't have access to configure IIS, you can still add the header through ASP.NET by adding the following line to your source pages:
Response.AppendHeader("Access-Control-Allow-Origin", "*");
See also: Configuring IIS6 / IIS7
Another option is to add it on the web.config directly:
<system.webServer>
<httpProtocol>
<customHeaders>
<add name="Access-Control-Allow-Origin" value="http://www.yourSite.com" />
<add name="Access-Control-Allow-Methods" value="GET, POST, PUT, DELETE, OPTIONS"/>
<add name="Access-Control-Allow-Headers" value="Origin, X-Requested-With, Content-Type, Accept" />
</customHeaders>
</httpProtocol>
...
I found this in here
1.Install-Package Microsoft.AspNet.WebApi.Cors
2 . Add this code in WebApiConfig.cs.
public static void Register(HttpConfiguration config)
{
// Web API configuration and services
// Web API routes
config.EnableCors();
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
3. Add this
using System.Web.Http.Cors;
4. Add this code in Api Controller (HomeController.cs)
[EnableCors(origins: "*", headers: "*", methods: "*")]
public class HomeController : ApiController
{
[HttpGet]
[Route("api/Home/test")]
public string test()
{
return "";
}
}
You would need an HTTP module that looked at the requested resource and if it was a css or js, it would tack on the Access-Control-Allow-Origin header with the requestors URL, unless you want it wide open with '*'.
Configuring the CORS response headers on the server wasn't really an option. You should configure a proxy in client side.
Sample to Angular - So, I created a proxy.conf.json file to act as a proxy server. Below is my proxy.conf.json file:
{
"/api": {
"target": "http://localhost:49389",
"secure": true,
"pathRewrite": {
"^/api": "/api"
},
"changeOrigin": true
}
}
Put the file in the same directory the package.json then I modified the start command in the package.json file like below
"start": "ng serve --proxy-config proxy.conf.json"
now, the http call from the app component is as follows:
return this.http.get('/api/customers').map((res: Response) => res.json());
Lastly to run use npm start or ng serve --proxy-config proxy.conf.json

Categories

Resources