Расширение атрибута Authorize
Я реализовал [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]
без всяких CustomRoles
, это определить строку по умолчанию, чтобы быть eUserRole.Administrator
, Это означает, что первый CustomAuthorize
вызываемый атрибут является атрибутом на уровне класса, а не на уровне метода.
Как заставить это вызывать атрибут, который есть у метода (Do()
) до?
1 ответ
Вас смущает тот факт, что 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 }
);
}
}
ПРИМЕЧАНИЕ. Технически вы можете хранить их обоих в одном классе, но это не так сложно, если вы разделяете их на компоненты, которые фактически есть, а не создаете один класс, который выполняет более одной работы (атрибут и фильтр).
Ссылка: пассивные атрибуты