扩展授权属性
Extending the Authorize attribute
我实现了一个基于 [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);
}
}
我将逻辑(谁接受谁不接受)拆分为分离 class。如果用户根据他的 CustomRoles
属性.
被接受,则方法 AuthorizationSystem.Validate()
return 为真
我的控制器看起来像:
[CustomAuthorize]
public class MyController : ApiController
{
[CustomAuthorize(CustomRoles = eUserRole.Readonly)]
public Response Do()
{
// ... Do something ...
}
}
我正在 运行 应用程序 (C# + WebAPI) 检查它是否工作。
我调试了代码,发现第一个 运行 所需的最低角色级别是 Administrator
而不是 Readonly
。因为在不使用任何 CustomRoles
的情况下使用 [CustomAuthorize]
时,它会将 default 行定义为 eUserRole.Administrator
。这意味着被调用的第一个 CustomAuthorize
属性是 class 级别的属性, 不是方法级别的属性 .
如何让它调用之前方法(Do()
)上的属性?
您对 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;
}
CustomAuthoizationFilter
这里我们通过子类化 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 }
);
}
}
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).
我实现了一个基于 [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);
}
}
我将逻辑(谁接受谁不接受)拆分为分离 class。如果用户根据他的 CustomRoles
属性.
AuthorizationSystem.Validate()
return 为真
我的控制器看起来像:
[CustomAuthorize]
public class MyController : ApiController
{
[CustomAuthorize(CustomRoles = eUserRole.Readonly)]
public Response Do()
{
// ... Do something ...
}
}
我正在 运行 应用程序 (C# + WebAPI) 检查它是否工作。
我调试了代码,发现第一个 运行 所需的最低角色级别是 Administrator
而不是 Readonly
。因为在不使用任何 CustomRoles
的情况下使用 [CustomAuthorize]
时,它会将 default 行定义为 eUserRole.Administrator
。这意味着被调用的第一个 CustomAuthorize
属性是 class 级别的属性, 不是方法级别的属性 .
如何让它调用之前方法(Do()
)上的属性?
您对 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;
}
CustomAuthoizationFilter
这里我们通过子类化 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 }
);
}
}
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).