Asp.net WebApi中的自定义授权 - 真是一团糟?

时间:2014-10-20 11:41:43

标签: asp.net authorization asp.net-web-api

我正在阅读有关WebApi授权的几个资源(书籍和SO答案)。

假设我想添加自定义属性,该属性仅允许对某些用户进行访问:

案例#1

我已经看到覆盖 OnAuthorization的这种方法,如果出现问题则设置响应

public class AllowOnlyCertainUsers : AuthorizeAttribute
{
 public override void OnAuthorization(HttpActionContext actionContext)
  {
   if ( /*check if user OK or not*/)
   {
     actionContext.Response = new HttpResponseMessage(HttpStatusCode.Unauthorized);
   }
  }
}

案例#2

但是我也看到了这个类似的例子,它也覆盖了OnAuthorization但是调用了base

public override void OnAuthorization(HttpActionContext actionContext) 
{ 
  base.OnAuthorization(actionContext);

    // If not authorized at all, don't bother

    if (actionContext.Response == null)  
     {
      //...
     }
}

然后,检查是否 是否设置了HttpActionContext.Response。如果未设置,则表示请求已获得授权且用户可以

案例#3

但我也看到了这种覆盖IsAuthorized的方法:

public class AllowOnlyCertainUsers : AuthorizeAttribute
{
 protected override bool IsAuthorized(HttpActionContext context)
  {
   if ( /*check if user OK or not*/)
   {
    return true;// or false
   }
  }
}

案例#4

然后我看到类似的例子,但是调用base.IsAuthorized(context):

protected override bool IsAuthorized(HttpActionContext context)
{
 if (something1 && something2 && base.IsAuthorized(context)) //??
 return true;
 return false;
}

还有一件事

最后,多米尼克说here

您不应该覆盖OnAuthorization - 因为您将缺少[AllowAnonymous]处理。

问题

  • 1)我应该使用哪种方法:IsAuthorizedOnAuthorization? (或何时使用)

  • 2)我何时应该致电base.IsAuthorized or base.OnAuthorization`?

  • 3)这是他们建造它的方式吗?如果响应为null则一切正常? (案例#2)

NB

请注意,我正在使用(并且只想使用)已经从AuthorizeAttribute

继承的AuthorizationFilterAttribute

为什么?

因为我在第一阶段:http://www.asp.net/web-api/overview/security/authentication-and-authorization-in-aspnet-web-api

enter image description here

无论如何我要求通过扩展Authorize属性。

3 个答案:

答案 0 :(得分:89)

  

我应该使用哪些方法:IsAuthorized还是OnAuthorization? ( 要么   何时使用哪个)

如果您的授权逻辑不依赖于已建立的身份和角色,您将扩展AuthorizationFilterAttribute。对于用户相关授权,您将扩展并使用AuthorizeAttribute。对于前一种情况,您将覆盖OnAuthorization。对于后一种情况,您将覆盖IsAuthorized。正如您从这些属性的源代码中看到的那样,OnAuthorization被标记为虚拟,如果您从AuthorizationFilterAttribute派生,则可以覆盖。另一方面,IsAuthorized方法在AuthorizeAttribute中标记为虚拟。我相信这是一个很好的指向预期用途的指针。

  

什么时候应该调用base.IsAuthorized或base.OnAuthorization?

这个问题的答案在于OO如何运作。如果覆盖方法,则可以完全提供新实现,也可以依靠父级提供的实现来增强行为。例如,以IsAuthorized(HttpActionContext)为例。基类行为是根据过滤器中指定的内容与建立的标识检查用户/角色。说,你想做所有这些,但另外,你想检查别的东西,可能是基于请求标题或其他东西。在这种情况下,您可以提供这样的覆盖。

protected override bool IsAuthorized(HttpActionContext actionContext)
{
    bool isAuthroized = base.IsAuthorized(actionContext);
    // Here you look at the header and do your additional stuff based on actionContext
    // and store the result in isRequestHeaderOk
    // Then, you can combine the results
    // return isAuthorized && isRequestHeaderOk;
}

对不起,但不明白你的Q3。 BTW,授权过滤器已经存在了很长时间,人们会将它用于各种事情,有时甚至是错误的。

  

还有一件事。最后这里有个人说:你   不应该覆盖OnAuthorization - 因为你会丢失   [AllowAnonymous]处理。

那个说是访问控制之神的人 - 多米尼克。显然这是正确的。如果你看一下OnAuthorization的实现(下面复制),

public override void OnAuthorization(HttpActionContext actionContext)
{
    if (actionContext == null)
    {
        throw Error.ArgumentNull("actionContext");
    }

    if (SkipAuthorization(actionContext))
    {
        return;
    }

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

SkipAuthorization的调用是确保应用AllowAnonymous过滤器的部分,即跳过授权。如果重写此方法,则会丢失该行为。实际上,如果您决定将授权基于用户/角色,那么您将决定从AuthorizeAttribute派生。只有正确的选项才能覆盖IsAuthorized,而不是已经覆盖的OnAuthorization,尽管技术上可以做到。

PS。在ASP.NET Web API中,还有另一个称为身份验证过滤器的过滤器。想法是您使用它进行身份验证和授权过滤器进行授权,如名称所示。但是,有很多这样的边界被捏造的例子。许多authroization过滤器示例将执行某种身份验证。无论如何,如果你有时间并希望了解更多,请查看此MSDN article。免责声明:这是我写的。

答案 1 :(得分:17)

好的,我的建议是假设您使用OAuth承载令牌来保护您的Web API并且您在发布令牌时将allowedTime设置为用户声明,请执行以下操作。您可以阅读有关token based authentication here

的更多信息
  1. 创建派生自AuthorizationFilterAttribute
  2. 的CustomAuthorizeAttribute
  3. 覆盖方法OnAuthorizationAsync并使用以下示例代码:

     public class CustomAuthorizeAttribute : AuthorizationFilterAttribute
    {
    
        public override Task OnAuthorizationAsync(HttpActionContext actionContext, System.Threading.CancellationToken cancellationToken)
        {
    
            var principal = actionContext.RequestContext.Principal as ClaimsPrincipal;
    
            if (!principal.Identity.IsAuthenticated)
            {
                return Task.FromResult<object>(null);
            }
    
            var userName = principal.FindFirst(ClaimTypes.Name).Value;
            var userAllowedTime = principal.FindFirst("userAllowedTime").Value;
    
            if (currentTime != userAllowedTime)
            {
                actionContext.Response = actionContext.Request.CreateResponse(HttpStatusCode.Unauthorized, "Not allowed to access...bla bla");
                return Task.FromResult<object>(null);
            }
    
            //User is Authorized, complete execution
            return Task.FromResult<object>(null);
    
        }
    }
    
  4. 现在,在您的控制器中,您使用CustomAuthorize属性来使用此授权逻辑保护您的控制器。

答案 2 :(得分:3)

ASP.NET v5 Introduced a completely new Authorization System. 对于那些打算使用.NET 5的人,我建议进入Microsoft.AspNet.Authorization。

它几乎包含了保持两者造成的混乱 System.Web.Http.AuthorizeSystem.Web.Mvc.Authorize以及其他较旧的身份验证实施。

它提供了动作类型(创建,读取,更新,删除),资源,角色,声明,视图,自定义要求的非常好的抽象,并允许构建自定义处理程序,结合上述任何一个。 此外,这些处理程序也可以组合使用。

  

在ASP.NET v5中,授权现在提供简单的声明性角色和a   更丰富的基于政策的模型,其中表示授权   要求和处理程序评估用户的声明   要求。强制性检查可以基于简单的策略或   评估用户身份和属性的策略   用户试图访问的资源。