简体   繁体   中英

Best way to handle unauthenticated request in asp.net Web Api

I have a standard VS2013 MVC5 project with a Web Api 2 in it. The way the standard project is designed, the [Authorize] attributes simply return a 401 status code if the request is not authenticated, while a totally separate module sniffs for any 401 codes, halts them, and instead sends a 302 redirect to the login page specified in the Startup.Auth.cs file. That's ok for Mvc controllers, but really stinks for Web Api controllers because for example browsers will automatically redirect ajax requests to the login url, so you ultimately end up with a 200OK status even though the response text is just the html of the login page.

That makes it hard to write good javascript that can distinguish between a case where you just need to tell the user to log back in versus other kinds of errors. Ideally we should be able to tell based on the status code, but javascript never ever sees the 401 status. What is the best way to handle this?

My first thought was to write an authorization attribute but use status code 403 instead of 401:

public class ApiAuthorizationAttribute : System.Web.Http.AuthorizeAttribute
{
    public override void OnAuthorization(System.Web.Http.Controllers.HttpActionContext actionContext)
    {
        if (actionContext.RequestContext.Principal.Identity.IsAuthenticated)
        {
            base.OnAuthorization(actionContext);
        }
        else
        {
            actionContext.Response = actionContext.ControllerContext.Request.CreateErrorResponse(HttpStatusCode.Forbidden, "Not signed in.");
        }
    }
}

Of course, specifications explicitly state that 403 is incorrect:

Authorization will not help and the request SHOULD NOT be repeated

My other thought is that maybe I should disable asp.net's 401 redirect module altogether and handle redirects in custom authorization attributes, because even for Mvc views it is lousy because it doesn't allow you to redirect to different login pages depending on where in the site the user is trying to visit.

Are there other, better approaches to handling this?

Here's what I was able to find with a bit more research. The 401 is intercepted by the OWIN middleware. But, OWIN does support branching configurations using the Map method. So in the Startup.cs file I have this:

public partial class Startup
{
    public void Configuration(IAppBuilder app)
    {
        app.Map(new PathString("/api"), site => ConfigureAuth2(site));
        ConfigureAuth(app);

    }
}

where ConfigureAuth is the default configuration method that comes in the Startup.Auth.cs file, while ConfigureAuth2 is a duplicate of that method but with the LoginPath option left unspecified in the UseCookieAuthentication method, which looks like this:

app.UseCookieAuthentication(new CookieAuthenticationOptions
        {
            AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
            Provider = new CookieAuthenticationProvider
            {
                // Enables the application to validate the security stamp when the user logs in.
                // This is a security feature which is used when you change a password or add an external login to your account.  
                OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<ApplicationUserManager, ApplicationUser>(
                    validateInterval: TimeSpan.FromMinutes(30),
                    regenerateIdentity: (manager, user) => user.GenerateUserIdentityAsync(manager))
            }
        });

According to the documentation , when the LoginPath is unspecified, 401 responses won't be intercepted for this branch.

So with this approach I'm branching all requests into two different configurations--all /api requests get configured not to redirect on 401 statuses, while everything else gets configured to redirect to the login page.

This SO question talked a bit about branching the configuration.

I'm still not sure if this is the best approach though.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM