【问题标题】:How to make ASP.NET Web API respond 403 or 401 appropriately?如何使 ASP.NET Web API 正确响应 403 或 401?
【发布时间】:2013-03-21 23:48:35
【问题描述】:

我正在使用 ASP.NET Web API。而且我确实喜欢添加属性以指定对 API 控制器的访问级别的能力,如下所示:

[Authorize]
public IEnumerable<Activity> Get()

到目前为止一切都很好,但是当我使用角色时,这个概念就崩溃了。

[Authorize(Roles = "Manager")]
public IEnumerable<Activity> Get()

我的用户可能在不久前登录了系统,然后在某个时候他们点击了对他们“禁止”的资源。用户尝试再次登录是没有意义的。由于他们的合法帐户无权访问该 URL。但目前他们得到的是 401(未经授权)而不是 403(禁止),就好像他们用错误的帐户登录一样。但用户只有一个帐号,并不打算让用户申请属于其他人的帐号。

还有其他人处理过这个问题吗?有谁知道如何解决这一问题?我非常愿意编写代码来解决这个问题,但我目前不知道从哪里开始。

【问题讨论】:

    标签: rest http authentication asp.net-web-api authorization


    【解决方案1】:

    阅读 Parv 的建议,我创建了以下名为 [WebApiAuthorize] 的自定义过滤器。

    关键是 HandleUnauthorizedRequest() 方法。当代码在这个方法中执行时,这是因为用户“出于某种原因”未经授权......所以现在我们只需确定“为什么”......然后:

    1. 为默认行为调用基方法(返回 401).... 或....
    2. 使用 403 返回我们自己的响应。

    如您所见,它在适当的时候返回 403(经过身份验证,但未授权)。

    public class WebApiAuthorizeAttribute : AuthorizeAttribute
    {
        protected override void HandleUnauthorizedRequest(HttpActionContext ctx)
        {
            if (!ctx.RequestContext.Principal.Identity.IsAuthenticated)
                base.HandleUnauthorizedRequest(ctx);
            else
            {
                // Authenticated, but not AUTHORIZED.  Return 403 instead!
                ctx.Response = new HttpResponseMessage(System.Net.HttpStatusCode.Forbidden);
            }
        }
    }
    

    要使用,只需将自定义过滤器扔到控制器或类似这样的操作上.....

    [WebApiAuthorize(Roles = "YourRoleA,YourRoleB")]
    public class AdminController : ApiController
    {
        public List<Admin> GetAdmins()
        {
            ...
        }
    } 
    

    【讨论】:

    • 小改进。您应该检查 Principal 或 Identity 是否为 null,否则当请求未提供凭据时,您可能会收到 NullReferenceException。protected bool IsAuthenticated(HttpActionContext ctx) { var principal = ctx.RequestContext.Principal; return principal != null &amp;&amp; principal.Identity != null &amp;&amp; principal.Identity.IsAuthenticated; }
    【解决方案2】:

    我做了一些研究,并为我编写了一个解决方案。我在 System.Web.Mvc 上找到了两个不同的 Authorize 属性,在 System.Web.Http 上找到了第二个。第一个适用于常规 MVC4 应用程序,第二个适用于用于 Web 服务的 MVC4 的 WebAPI 部分,包括 RESTful 接口。所以我用了第二个。

    我决定查看 codeplex 的 Authorize Attribute Source 代码。我发现了这个:

        protected virtual bool IsAuthorized(HttpActionContext actionContext)
        {
            if (actionContext == null)
            {
                throw Error.ArgumentNull("actionContext");
            }
    
            IPrincipal user = Thread.CurrentPrincipal;
            if (user == null || !user.Identity.IsAuthenticated)
            {
                return false;
            }
    
            if (_usersSplit.Length > 0 && !_usersSplit.Contains(user.Identity.Name, StringComparer.OrdinalIgnoreCase))
            {
                return false;
            }
    
            if (_rolesSplit.Length > 0 && !_rolesSplit.Any(user.IsInRole))
            {
                return false;
            }
    
            return true;
        }
    

    很容易看出身份验证和访问是如何混为一谈的,因为它们都具有返回 false 的相同效果。

    这是我写的new AuthorizeAttribute,当用户或角色不匹配时返回 403。这样您就可以避免获得本机登录窗口。它包括以下代码。

            if (!IsAuthorized(actionContext))
            {
                HandleUnauthorizedRequest(actionContext);
            }
    
            if (!IsAllowed(actionContext))
            {
                HandleForbiddenRequest(actionContext);
            }
    

    【讨论】:

    • 不情愿地投了赞成票;您应该在此处引用HandleUnathorizedRequest() 和/或HandleForbiddenRequest() 的代码,这样我们就不必按照您的要点链接。
    【解决方案3】:

    你可以做一个自定义Authorize attribute 然后处理 AuthorizeCoreOnAuthorizationFailed 在后一个中,您可以发送您喜欢的任何回复

    有一个look here

    【讨论】:

    • 修改 AuthorizeAttribue 就是答案。该特定示例是修改 System.Web.Mvc 而不是 System.Web.Http,因为我使用的是 WebAPI。
    • 我以为你想创建一个自定义属性来发回你喜欢的 Http 状态代码
    • 这就是我所做的,我继承自 System.Web.Http.AuthorizeAtribute。不是来自 System.Web.Mvc.AuthorizeAtribute ,这是您指出的文章所指的内容。
    • 如果您想处理请求授权失败后发送的自定义代码,或者您可以从 AutorizeFilterAttribute 继承
    猜你喜欢
    • 2020-08-06
    • 2015-09-21
    • 2020-07-06
    • 1970-01-01
    • 1970-01-01
    • 2016-08-02
    • 2011-03-18
    • 1970-01-01
    相关资源
    最近更新 更多