Find the Method that will be executed in the controller using reflection
I'm maintaining an ASP.NET MVC site where they are doing their own security. So they have created a class derived from AuthorizeAttribute
. In the OnAuthorization
, they have some reflection code that finds the method based on the action
name in RouteData
.
The problem that I see, is that if you have multiple action functions in the controller, that differ by only AcceptVerb
, or parameters, it will possible not authorize the user:
IList<MethodInfo> methods = filterContext.Controller.GetType().GetMethods().Where(i=>i.Name == action).ToList();
foreach (MethodInfo method in methods)
{
//get all of the controller security pr开发者_运维百科operties, and check for access:
object[] props = method.GetCustomAttributes(typeof(ControllerSecurity), false);
foreach (ControllerSecurity prop in props)
{
//does the user have access to this area/action?
authorized = security.ValidateUserForAction(prop.SecurityArea, prop.SecurityAction);
//if we are authorized by one ControllerSecurity, then we are good.
if (authorized)
{
break;
}
}
}
The ControllerSecurity
class is an Attribute class used to decorate our controller actions, and describe the security access required for this function:
//User needs to have VIEW privileges to REPORTS area:
[ControllerSecurity("REPORTS", "VIEW")]
public ActionResult Index(){...}
There must be a better way of doing this, without rewriting the security. I would like to know with some certainty that we only check the method that will be eventually run.
I've looked through the AuthorizationContext
object, and can't find anyway to reliably find the action method that will be eventually called.
Anyone have any ideas?
I think Mvc gives you a way to access the particular action already. I haven't tried it but try this..
object[] props = filterContext.ActionDescriptor.GetCustomAttributes(typeof(ActionMethodSelectorAttribute), false);
foreach (ActionMethodSelectorAttribute prop in props)
{
//does the user have access to this area/action?
authorized = security.ValidateUserForAction(prop.SecurityArea, prop.SecurityAction);
//if we are authorized by one ControllerSecurity, then we are good.
if (authorized)
{
break;
}
}
The thing to note is filterContext.ActionDescriptor, it exists in the AuthorizationContext that is passed in in the OnAuthorization
method.
If that doesn't work, you might look into using ActionNameSelectorAttribute
in your action finding code. The code you showed won't always work. Take the case of someone explicitly using ActionName["MyAction"]
to define the action instead of the implied method name.
精彩评论