18

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

[Authorize]
public IEnumerable<Activity> Get()

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

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

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

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

4

3 回答 3

35

阅读 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()
    {
        ...
    }
} 
于 2015-05-08T19:19:19.843 回答
2

我做了一些研究,并为我编写了一个解决方案。我在 System.Web.Mvc 和 System.Web.Http 中发现了两个不同的 Authorize 属性。第一个适用于常规 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 的相同效果。

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

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

        if (!IsAllowed(actionContext))
        {
            HandleForbiddenRequest(actionContext);
        }
于 2013-04-02T15:23:17.490 回答
0

您可以做的是进行自定义Authorize attribute,然后处理 AuthorizeCoreOnAuthorizationFailed在后者中,您可以发送您喜欢的任何响应

看看这里

于 2013-03-31T20:56:12.823 回答