Wednesday, May 23, 2018

Make Web API authentication return 401 instead of redirect to login page

Leave a Comment

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.

If You Enjoyed This, Take 5 Seconds To Share It

0 comments:

Post a Comment