[英]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
实现Attribute
和IAuthorizationFilter
的事实感到困惑。 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. 然后,您可以确定哪个优先于另一个。
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
public class CustomAuthorizeAttribute : Attribute
{
public eUserRole CustomRoles { get; set; } = eUserRole.Administrator;
}
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;
}
}
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.