是知道对方的多个授权属性 [英] Multiple authorization attributes that are aware of each other
问题描述
我有一个非常简单的场景。我想装饰与自定义授权属性我控制器/行动。如果的任何属性的有效授权应予以批准。例如,
I have a very simple scenario. I want to decorate my controllers/actions with a custom authorization attribute. Authorization should be granted if any of the attributes is valid. For example,
[MyAuth(1)]
[MyAuth(2)]
public class MyController : Controller
{
...
}
我不能参数组合成一个单一的授权属性。上面的例子是一个简单的例子,只有
I cannot combine the parameters into a single authorization attribute. The above example is a simplified example, only.
如果任一属性授权用户,我希望用户进行授权。我以为, ActionFilterAttribute
或 AuthorizeAttribute
将不得不看到已经执行了哪些其他过滤器的手段,正在等待被执行,但没有这样的运气。
If either attribute authorizes the user, I want the user to be authorized. I assumed that ActionFilterAttribute
or AuthorizeAttribute
would have the means to see what other filters have been executed and are waiting to be executed, but no such luck.
我怎样才能做到这一点?由于属性似乎没有任何意识,也许一个的HttpModule
?自定义 ControllerActionInvoker
?
How can I accomplish this? Since the attributes don't seem to have any awareness, maybe an HttpModule
? A custom ControllerActionInvoker
?
推荐答案
我设法得到这个昨晚工作。我的解决方案如下。该属性是pretty标准,我已经修剪实际的授权部分。有趣的事情发生在 HasAssignedAcccessActionInvoker
。
I managed to get this to work last night. My solution is below. The attribute is pretty standard and I've trimmed the actual authorization parts. The interesting stuff happens in 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
方法来添加我们需要的授权逻辑。标准调用只是旋转通过授权过滤器和其中是否返回一个结果,它打破了循环。
HasAssignedAcccessActionInvoker
inherits from the standard action invoker, but I overrode the InvokeAuthorizationFilters
method to add the authorization logic we need. The standard invoker just spins through the authorization filters and if any of them returns a result, it breaks the loop.
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内部摸不着头脑。作为参考,这是该方法的重写版本:
I had to look at MVC's internals with ILSpy to figure this out. For reference, this is the overridden version of that method:
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
,它现在返回新的调用。
Lastly, to wire this up and make everything possible, our controllers inherit from BaseController
, which now returns the new invoker.
public class BaseController : Controller
{
protected override IActionInvoker CreateActionInvoker()
{
return new HasAssignedAcccessActionInvoker();
}
}
这篇关于是知道对方的多个授权属性的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!