I have Web API with OWIN Authentication in Web MVC. I'm using <authentication>
in Web.Config for my Web MVC so it's redirecting to login page.
<authentication mode="Forms"> <forms name="WEB.AUTH" loginUrl="~/login" domain="" protection="All" timeout="43200" path="/" requireSSL="false" slidingExpiration="true" /> </authentication>
I'm using [System.Web.Http.Authorize]
attribute to authorize my Web API. But somehow, the API redirecting to login page same like my MVC app because of above configuration.
what I want to do is keep redirecting function for the Web MVC but returning 401 for Web API. How can I achieve this? should I create a custom authorization attribute for Web API?
--EDIT--
I found the answer from this post SuppressDefaultHostAuthentication in WebApi.Owin also suppressing authentication outside webapi
So I just add a few lines into my Startup.cs
. I had all my controllers configured with a "api" prefix route.
HttpConfiguration config = new HttpConfiguration(); //..some OWIN configuration app.Map("/api", inner => { inner.UseWebApi(config); });
make sure you put app.Map()
after Web Api Configuration lines. Otherwise, it will give error to MVC application.
3 Answers
Answers 1
Create a custom AuthorizeAttribute
:
public class MyAuthorizeAttribute : AuthorizeAttribute { protected override void HandleUnauthorizedRequest(HttpActionContext actionContext) { actionContext.Response = actionContext.Request.CreateErrorResponse(HttpStatusCode.Unauthorized, "Unauthorized"); } }
If you in the future skip the web.config stuff and use owin to setup your authentication, you could in your Startup.cs
do:
var provider = new CookieAuthenticationProvider(); var originalHandler = provider.OnApplyRedirect; provider.OnApplyRedirect = context => { if (!context.Request.Uri.LocalPath.StartsWith(VirtualPathUtility.ToAbsolute("~/api"))) { context.RedirectUri = new Uri(context.RedirectUri).PathAndQuery; originalHandler.Invoke(context); } }; app.UseCookieAuthentication(new CookieAuthenticationOptions { AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie, CookieName = FormsAuthentication.FormsCookieName, LoginPath = new PathString("/Account/LogOn"), ExpireTimeSpan = TimeSpan.FromMinutes(240), Provider = provider });
Answers 2
This is what worked for me.
Creating a custom attribute:
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = true)] public class NoRedirectAuthorizeAttribute : AuthorizeAttribute { protected override void HandleUnauthorizedRequest(HttpActionContext actionContext) { actionContext.Response = new System.Net.Http.HttpResponseMessage(System.Net.HttpStatusCode.Forbidden); } }
Using the attribute in your controller:
[HttpDelete] [NoRedirectAuthorizeAttribute(Roles = "Admin")] [Route("api/v3/thingstodelete/{id=id}")] public IHttpActionResult DeleteThingToDelete(Guid id) { //delete code }
Here are just overriding the HandleUnauthorizedRequest method of the AuthorizeAttribute. So, instead of sending a redirect (304) to the login page, we send Forbidden(403) HTTP status code.
Answers 3
In order to change the way IIS behaves based on a convention defined by URL, you want to branch your OWIN pipeline. You can do this by using IApplicationBuilder.Map
. Assuming a static config
:
public void Configure(IApplicationBuilder app) { ... app.Map("/api", HandleWebApiRequests); ... } private static void HandleWebApiRequests(IApplicationBuilder app) { app.UseWebApi(config); }
The Map
method branches the pipeline to the HandleWebApiRequests
method based on an URL that begins with "/api"
.
This should cause 401 errors to behave like they are supposed to and simply return 401 with no redirect.
0 comments:
Post a Comment