我已根据[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()
)之前的属性?
答案 0 :(得分:2)
AuthorizeAttribute
实现了Attribute
和IAuthorizationFilter
这一事实让您感到困惑。您需要做的是创建一个全局注册的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
属性优先。这是设置为使操作方法覆盖控制器,但如果需要,您可以使逻辑更复杂。
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 }
);
}
}
注意:从技术上讲,您可以将它们保存在同一个类中,但如果将它们分成实际上的组件而不是制作单个类,它可以执行多个作业(属性和过滤器)。