【问题标题】:Extending the Authorize attribute扩展授权属性
【发布时间】:2018-08-16 21:56:06
【问题描述】:

我基于[Authorize] 属性实现了[CustomAuthorization] 属性。我的属性如下所示:

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

我将逻辑(谁接受谁不接受)拆分为单独的类。如果用户根据其CustomRoles 属性被接受,则AuthorizationSystem.Validate() 方法返回true。

我的控制器看起来像:

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

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

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

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

【问题讨论】:

  • 拥有一个具有最低管理员访问权限的控制器似乎有点奇怪,但该控制器的方法具有最低只读权限。你的逻辑自相矛盾。

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


【解决方案1】:

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

自定义授权属性

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

自定义授权过滤器

这里我们通过子类化AuthorizeAttribute 节省了一些步骤,但我们根本不打算将其作为Attribute,而只是一个全局注册的过滤器。

我们的过滤器包含反射代码,用于确定如果两个CustomAuthorize 属性都已定义,则哪个属性优先。这是为了让 action 方法覆盖控制器,但如果需要,您可以使逻辑更复杂。

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-02-04
    • 1970-01-01
    • 2011-04-29
    • 2023-03-12
    • 2018-04-30
    相关资源
    最近更新 更多