简体   繁体   English

处理asp.net Web Api中未经身份验证的请求的最佳方法

[英]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. 我有一个带有Web Api 2的标准VS2013 MVC5项目。 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. 标准项目的设计方式是,如果未对请求进行身份验证, [Authorize]属性仅返回401状态代码,而完全独立的模块将嗅探任何401代码,并将其暂停,然后将302重定向发送到登录页面在Startup.Auth.cs文件中指定。 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. 对于Mvc控制器而言,这是可以的,但对于Web Api控制器而言却确实很臭,因为例如浏览器会自动将ajax请求重定向到登录网址,因此即使响应文本只是登录页面的html,您最终还是以200OK状态结束。

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. 这就使得很难编写出色的javascript来区分您只需要告诉用户重新登录的情况和其他类型的错误。 Ideally we should be able to tell based on the status code, but javascript never ever sees the 401 status. 理想情况下,我们应该能够根据状态代码来判断,但是javascript永远不会看到401状态。 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: 我的第一个想法是编写一个授权属性,但使用状态码403而不是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: 当然, 规范明确指出403不正确:

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. 我的另一个想法是,也许我应该完全禁用asp.net的401重定向模块,并处理自定义授权属性中的重定向,因为即使对于Mvc视图,它也很糟糕,因为它不允许您根据在哪个位置重定向到不同的登录页面。用户尝试访问的站点。

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. 401被OWIN中间件拦截。 But, OWIN does support branching configurations using the Map method. 但是,OWIN确实支持使用Map方法的分支配置。 So in the Startup.cs file I have this: 所以在Startup.cs文件中,我有这个:

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: 其中, ConfigureAuthStartup.Auth.cs文件中的默认配置方法,而ConfigureAuth2是该方法的副本,但UseCookieAuthentication方法中未指定LoginPath选项,如下所示:

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. 根据文档 ,未指定LoginPath时,此分支不会拦截401响应。

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. 因此,通过这种方法,我将所有请求分为两个不同的配置-所有/api请求都配置为不重定向401状态,而其他所有配置都重定向为登录页面。

This SO question talked a bit about branching the configuration. 这个SO问题讨论了有关分支配置的问题。

I'm still not sure if this is the best approach though. 我仍然不确定这是否是最好的方法。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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