扩展Authorize属性

时间:2018-03-08 14:00:49

标签: c# asp.net asp.net-web-api oauth owin

我已根据[CustomAuthorization]属性实施了[Authorize]属性。我的属性如下所示:

public class CustomAuthorizeAttribute : AuthorizeAttribute
{
    public eUserRole CustomRoles { get; set; } = eUserRole.Administrator; // If not specified, the required role is Administrator

    protected override bool IsAuthorized(HttpActionContext actionContext)
    {
        AuthorizationSystem auth = new AuthorizationSystem(actionContext.RequestContext.Principal, this.CopyleaksRoles);
        var res = auth.Validate();
        if (!res)
            return false;

        return base.IsAuthorized(actionContext);
    }
}

我将逻辑(接受和不接受的人)拆分为分离的类。如果根据用户AuthorizationSystem.Validate()属性接受用户,方法CustomRoles将返回true。

我的控制器看起来像:

[CustomAuthorize]
public class MyController : ApiController
{
    [CustomAuthorize(CustomRoles = eUserRole.Readonly)]
    public Response Do()
    {
        // ... Do something ...
    }
}

我正在运行应用程序(C#+ WebAPI)来检查它是否正常工作。

我调试代码并在第一次运行时看到所需的最低角色级别为Administrator而不是Readonly。因为在没有任何[CustomAuthorize]的情况下使用CustomRoles时,它会将默认行定义为eUserRole.Administrator。这意味着被调用的第一个CustomAuthorize属性是类级别的属性,不是方法级别

如何让它调用方法(Do())之前的属性?

1 个答案:

答案 0 :(得分:2)

AuthorizeAttribute实现了AttributeIAuthorizationFilter这一事实让您感到困惑。您需要做的是创建一个全局注册的IAuthorizationFilter并使用它来确定操作或控制器上是否存在CustomAuthorizeAttribute。然后你可以确定哪个优先于另一个。

CustomAuthorizeAttribute

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
public class CustomAuthorizeAttribute : Attribute
{
    public eUserRole CustomRoles { get; set; } = eUserRole.Administrator;
}

CustomAuthoizationFilter

这里我们通过继承AuthorizeAttribute来保存一些步骤,但我们并不打算将它作为Attribute,而只是全局注册的过滤器。

我们的过滤器包含反射代码,用于确定在定义两者时CustomAuthorize属性优先。这是设置为使操作方法覆盖控制器,但如果需要,您可以使逻辑更复杂。

public class CustomAuthorizationFilter : AuthorizeAttribute
{
    protected override bool IsAuthorized(HttpActionContext actionContext)
    {
        if (base.IsAuthorized(actionContext))
        {
            var authorizeAttribute = GetAuthorizeAttribute(actionContext.ActionDescriptor);

            // Attribute doesn't exist - return true
            if (authorizeAttribute == null)
                return true;

            var roles = authorizeAttribute.CustomRoles;

            // Logic - return true if authorized, false if not authorized

        }

        return false;
    }

    private CustomAuthorizeAttribute GetAuthorizeAttribute(HttpActionDescriptor actionDescriptor)
    {
        // Check action level
        CustomAuthorizeAttribute result = actionDescriptor
            .GetCustomAttributes<CustomAuthorizeAttribute>()
            .FirstOrDefault();

        if (result != null)
            return result;

        // Check class level
        result = actionDescriptor
            .ControllerDescriptor
            .GetCustomAttributes<CustomAuthorizeAttribute>()
            .FirstOrDefault();

        return result;
    }
}

用法

我们在全球注册过滤器。对于每个请求,CustomAuthorizationFilter扫描请求中的操作和控制器以查看该属性是否存在。如果是,则运行逻辑。

public static class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {
        // Web API configuration and services
        // Configure Web API to use only bearer token authentication.
        config.SuppressDefaultHostAuthentication();
        config.Filters.Add(new HostAuthenticationFilter(OAuthDefaults.AuthenticationType));

        // Register our Custom Authorization Filter
        config.Filters.Add(new CustomAuthorizationFilter());

        // Web API routes
        config.MapHttpAttributeRoutes();

        config.Routes.MapHttpRoute(
            name: "DefaultApi",
            routeTemplate: "api/{controller}/{id}",
            defaults: new { id = RouteParameter.Optional }
        );
    }
}
  

注意:从技术上讲,您可以将它们保存在同一个类中,但如果将它们分成实际上的组件而不是制作单个类,它可以执行多个作业(属性和过滤器)。

参考:Passive Attributes