简体   繁体   English

扩展授权属性

[英]Extending the Authorize attribute

I'm implemented a [CustomAuthorization] attribute based on [Authorize] attribute. 我基于[Authorize]属性实现了[CustomAuthorization] [Authorize]属性。 My attribute looks like this: 我的属性如下所示:

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

I splitted the logic (who to accept and who not) to seperated class. 我将逻辑(谁接受和谁不接受)划分为单独的课程。 The method AuthorizationSystem.Validate() return true if the user is accepted according to his CustomRoles property. 如果根据其CustomRoles属性接受了用户,则AuthorizationSystem.Validate()方法将返回true。

My Controller looks like: 我的控制器看起来像:

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

I'm running the application (C# + WebAPI) to check if it working. 我正在运行应用程序(C#+ WebAPI),以检查其是否正常运行。

I debugging the code and see that on the first run the minimum required role level is Administrator instead of Readonly . 我调试了代码,看到第一次运行时,最低要求的角色级别是Administrator而不是Readonly Because when using [CustomAuthorize] without any CustomRoles , it's define the default row to be eUserRole.Administrator . 因为在不使用任何CustomRoles情况下使用[CustomAuthorize] ,会将默认行定义为eUserRole.Administrator That mean that the first CustomAuthorize attribute that being called is the attribute on class level, not on method level . 这意味着被调用的第一个CustomAuthorize属性是类级别的属性, 而不是方法级别的属性。

How to make it call the attribute that on the method ( Do() ) before? 如何使其调用方法( Do() )之前的属性?

You are getting confused by the fact that AuthorizeAttribute implements both Attribute and IAuthorizationFilter . 您对AuthorizeAttribute实现AttributeIAuthorizationFilter的事实感到困惑。 What you need to do is make a globally registered IAuthorizationFilter and use it to determine whether the CustomAuthorizeAttribute exists on the action or controller. 您需要做的是创建一个全局注册的IAuthorizationFilter并使用它来确定Action或控制器上是否存在CustomAuthorizeAttribute Then you can determine which takes precedence over the other. 然后,您可以确定哪个优先于另一个。

CustomAuthorizeAttribute CustomAuthorizeAttribute

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

CustomAuthoizationFilter CustomAuthoizationFilter

Here we save some steps by subclassing AuthorizeAttribute , but we don't intend for this to be an Attribute at all, only a globally registered filter. 在这里,我们通过对AuthorizeAttribute进行子类化来保存一些步骤,但是我们根本不打算将其成为Attribute ,而只是将其作为全局注册的过滤器。

Our filter contains Reflection code to determine which CustomAuthorize attribute takes precedence if both are defined. 我们的过滤器包含反射代码,以确定同时定义了哪个CustomAuthorize属性优先。 This is setup to make the action method override the controller, but you can make the logic more complex, if needed. 进行设置是为了使操作方法优先于控制器,但是如果需要,可以使逻辑更复杂。

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

Usage 用法

We register the filter globally. 我们在全球范围内注册过滤器。 For each request, CustomAuthorizationFilter scans the action and controller in the request to see if the attribute exists. 对于每个请求, CustomAuthorizationFilter扫描请求中的操作和控制器,以查看该属性是否存在。 If so, it then runs the logic. 如果是这样,那么它将运行逻辑。

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

NOTE: Technically you can keep them both in the same class, but it is less confusing if you separate them into the components that that actually are rather than making a single class that does more than one job (attribute and filter). 注意:从技术上讲,您可以将它们放在同一个类中,但是,如果将它们分成实际上是一个组件,而不是制作一个可以完成一项以上工作(属性和过滤器)的类,则不会造成混淆。

Reference: Passive Attributes 参考: 被动属性

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM