代码之家  ›  专栏  ›  技术社区  ›  No1Lives4Ever

扩展Authorize属性

  •  2
  • No1Lives4Ever  · 技术社区  · 7 年前

    我执行了一个 [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() 如果用户根据其权限被接受,则返回true CustomRoles 所有物

    我的控制器看起来像:

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

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

    我调试了代码,发现在第一次运行时,所需的最低角色级别是 Administrator 而不是 Readonly 。因为使用时 [CustomAuthorize] 没有任何 自定义角色 ,定义 违约 待处理行 eUserRole.Administrator 。这意味着 CustomAuthorize 被调用的属性是类级别的属性, 不在方法级别

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

    1 回复  |  直到 7 年前
        1
  •  4
  •   NightOwl888 Jabrwoky    7 年前

    你被以下事实弄糊涂了 AuthorizeAttribute 实现两个 Attribute IAuthorizationFilter 。您需要做的是进行全球注册 IAuthorizationFilter 并使用它来确定 CustomAuthorizeAttribute 存在于操作或控制器上。然后您可以确定哪个优先于另一个。

    CustomAuthorizeAttribute

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

    CustomAuthorization筛选器

    在这里,我们通过子类化来保存一些步骤 授权属性 ,但我们不打算 属性 实际上,只有一个全局注册的过滤器。

    我们的过滤器包含反射代码来确定 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