在asp.net Web Api中处理未经验证请求的最佳方式

本文关键字:验证 请求 方式 最佳 处理 net asp Web Api | 更新日期: 2023-09-27 18:27:06

我有一个标准的VS2013 MVC5项目,其中包含Web Api 2。按照标准项目的设计方式,如果请求未通过身份验证,[Authorize]属性只会返回401状态代码,而一个完全独立的模块会嗅探任何401代码,停止它们,并将302重定向到Startup.Auth.cs文件中指定的登录页。这对Mvc控制器来说没问题,但对WebApi控制器来说真的很糟糕,因为例如浏览器会自动将ajax请求重定向到登录url,所以即使响应文本只是登录页面的html,最终也会显示200OK状态。

这使得编写好的javascript很难区分只需要告诉用户重新登录的情况和其他类型的错误。理想情况下,我们应该能够根据状态代码进行判断,但javascript永远不会看到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.");
        }
    }
}

当然,规范明确指出403是不正确的:

授权没有帮助,请求不应重复

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

有没有其他更好的方法来处理这个问题?

在asp.net Web Api中处理未经验证请求的最佳方式

以下是我通过更多研究发现的内容。401被OWIN中间件截获。但是,OWIN确实支持使用Map方法的分支配置。所以在Startup.cs文件中,我有这个:

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

其中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))
            }
        });

根据文档,当未指定LoginPath时,该分支将不会截获401个响应。

因此,通过这种方法,我将所有请求分为两种不同的配置——所有/api请求都被配置为不重定向401状态,而其他所有请求都被设置为重定向到登录页面。

这个SO问题讨论了一些关于分支配置的问题。

不过,我仍然不确定这是否是最好的方法。