Прошлой ночью мне удалось заставить это работать. Мое решение ниже. Атрибут довольно стандартный, и я обрезал фактические части авторизации. Интересные вещи происходят в HasAssignedAcccessActionInvoker
.
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true)]
public class RequiresAssignedAccess : AuthorizeAttribute
{
public int AccessType { get; private set; }
public int IdType { get; private set; }
public int IdValue { get; private set; }
public int Level { get; private set; }
public RequiresAssignedAccess(int accessType, int idType, int idValue, int level)
{
...
}
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
if (!base.AuthorizeCore(httpContext))
return false;
bool retval = ...
return retval;
}
}
HasAssignedAcccessActionInvoker
унаследован от стандартного вызывающего действия, но я переопределил метод InvokeAuthorizationFilters
, чтобы добавить необходимую нам логику авторизации. Стандартный вызывающий элемент просто прокручивает фильтры авторизации, и если какой-либо из них возвращает результат, он прерывает цикл.
public class HasAssignedAcccessActionInvoker : ControllerActionInvoker
{
protected override AuthorizationContext InvokeAuthorizationFilters(ControllerContext controllerContext, IList<IAuthorizationFilter> filters, ActionDescriptor actionDescriptor)
{
AuthorizationContext authCtx = new AuthorizationContext(controllerContext, actionDescriptor);
/*
* If any of the filters are RequiresAssignedAccess, default this to false. One of them must authorize the user.
*/
bool hasAccess = !filters.Any(f => f is RequiresAssignedAccess);
foreach (IAuthorizationFilter current in filters)
{
/*
* This sets authorizationContext.Result, usually to an instance of HttpUnauthorizedResult
*/
current.OnAuthorization(authCtx);
if (current is RequiresAssignedAccess)
{
if (authCtx.Result == null)
{
hasAccess = true;
}
else if (authCtx.Result is HttpUnauthorizedResult)
{
authCtx.Result = null;
}
continue;
}
if (authCtx.Result != null)
break;
}
if (!hasAccess && authCtx.Result == null)
authCtx.Result = new HttpUnauthorizedResult();
return authCtx;
}
}
Чтобы понять это, мне пришлось взглянуть на внутреннее устройство MVC с помощью ILSpy. Для справки, это переопределенная версия этого метода:
protected virtual AuthorizationContext InvokeAuthorizationFilters(ControllerContext controllerContext, IList<IAuthorizationFilter> filters, ActionDescriptor actionDescriptor)
{
AuthorizationContext authorizationContext = new AuthorizationContext(controllerContext, actionDescriptor);
foreach (IAuthorizationFilter current in filters)
{
current.OnAuthorization(authorizationContext);
if (authorizationContext.Result != null)
{
break;
}
}
return authorizationContext;
}
Наконец, чтобы связать это и сделать все возможное, наши контроллеры наследуют от BaseController
, который теперь возвращает новый вызывающий объект.
public class BaseController : Controller
{
protected override IActionInvoker CreateActionInvoker()
{
return new HasAssignedAcccessActionInvoker();
}
}
person
Community
schedule
06.11.2013
HttpModule
? Когда я взламываю, я бы выбрал msdn.microsoft.com/en-us/library/. Но почему вы не можете комбинировать параметры? - person Andreas   schedule 05.11.2013HttpModule
. Я предлагал это как возможное решение. - person   schedule 05.11.2013