I am decorating my controller actions with an AuthorizeAttribute.
[ServiceAuthorize(Roles="Editor,Publisher,Administrator")]
public JsonResult Create(NewsArticle newsArticle)
There is a field in my NewsArticle model that I would like to use in the OnAuthorize method in my AuthorizeAttribute.
Is there any way to get at the model from within the OnAuthorize method of the AuthorizeAttribute?
I assumed it would be available within the AuthorizationContext somewhere but I can't find it. I know I can get to it in the ActionExecutingContext of a filter attribute but that means I would need another filter on my action and I would like to be able to perform all the authorization in a single step.
Thanks.
Is there any way to get at the model from within the OnAuthorize method of the AuthorizeAttribute?
No because the OnAuthorization runs before the model binder. What you could do is to read the value from the value provider:
public override void OnAuthorization(AuthorizationContext filterContext)
{
var value = filterContext.Controller.ValueProvider.GetValue("someproperty");
...
}
I was trying to accomplish the same thing, basically wanting to control authorization with attributes on the action method parameters, as an example:
[MyAuthorize]
public ActionResult MyAction(
[Require(Permission.Write)] MyCustomObject arg1,
[Require(Permission.Read)] MyCustomObject arg2
) {
// ... all authorization would be handled before the action is invoked ...
}
class MyAuthorize : AuthorizeAttribute {
public override void OnAuthorization(AuthorizationContext filterContext) {
// ... filterContext doesn't have the argument objects ...
}
}
I ran into the same issue, when overriding AuthorzeAttribute.OnAuthorization(...)
the model bound arguments don't exist yet. To accomplish what I needed, I implemented IActionFilter
which exposes a method OnActionExecuting
that will be called after the model is bound but before the action is invoked. My prototype implementation looks like this:
class MyAuthorizeAttribute : AuthorizeAttribute, IActionFilter {
public override void OnAuthorization(AuthorizationContext filterContext) {
// ... I guesss this isn't really needed any more.
// the auth check is handled in OnActionExecuting.
}
void IActionFilter.OnActionExecuted(ActionExecutedContext filterContext) {
}
void IActionFilter.OnActionExecuting(ActionExecutingContext filterContext) {
foreach (var param in filterContext.ActionDescriptor.GetParameters()) {
var attr = (RequireAttribute)param.GetCustomAttributes(typeof(RequireAttribute), false).FirstOrDefault();
if(attr != null) {
Object obj;
if (filterContext.ActionParameters.TryGetValue(param.ParameterName, out obj)) {
var sec = obj as ISecurable;
if (sec == null || !sec.HasPermission(filterContext.RequestContext, attr.Permission)) {
filterContext.Result = new HttpStatusCodeResult(System.Net.HttpStatusCode.Unauthorized);
}
}
}
}
}
}
interface ISecurable {
bool HasPermission(Permission permission);
}
This is just a proof of concept for a project I'm working on, but it seems like a workable solution.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With