I'm trying to peek at any authentication attributes which may be decorating action methods in my controllers in an MVC 3 application. I'm doing this in my own HtmlHelper extension methods which are basically wrappers to ActionLink (to give you the context of what information I have available at runtime). I have a basic solution in place, but overloaded methods have just made it explode. I know that the framework is internally resolving urls to action methods, but after looking through the code for System.Web.Mvc.LinkExtensions, I still haven't found precisely how that is happening, so I'm a bit stuck as to how to tackle this issue.
Here's the code I have so far for resolving the relevant method:
private static bool _IsUserAuthorized(HtmlHelper html,
string controllerName, string actionName)
{
controllerName = controllerName ??
html.ViewContext.RouteData.GetRequiredString("controller");
var factory = ControllerBuilder.Current.GetControllerFactory();
var controller = factory.CreateController(
html.ViewContext.RequestContext, controllerName);
Type controllerType = controller.GetType();
var methodInfo = controllerType.GetMethod(actionName,
BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance);
... check authentication
}
So my current problem is that when a method is overridden, I get "ambiguous match found" exceptions. I'm guessing I need to process the RouteValues to resolve any parameters to the method so I can unambiguously identify the right one. Does anyone have some pointers on how to do this? Alternately, does the framework already provide a means of resolving the exact method needed?
Thanks so much!
Action selector is the attribute that can be applied to the action methods. It helps the routing engine to select the correct action method to handle a particular request.
ActionName attribute is an action selector which is used for a different name of the action method. We use ActionName attribute when we want that action method to be called with a different name instead of the actual name of the method.
EDIT: Updated the method to include insights from this page. This final version peeks the AuthorizationFilters for the requested action method and checks whether the user is authorized to perform the action.
So I dug around in System.Web.Mvc.ControllerActionInvoker and found the methods and constructors I needed. ControllerDescriptor.FindAction() ended up being the key. Below, I've copied the method I wrote that will retrieve all the attributes
private static bool _IsUserAuthorized(HtmlHelper htmlHelper,
string controllerName, string actionName)
{
ControllerContext controllerContext = null;
//if controllerName is null or empty, we'll use the
// current controller in HtmlHelper.ViewContext.
if (string.IsNullOrEmpty(controllerName))
{
controllerContext = htmlHelper.ViewContext.Controller.ControllerContext;
}
else //use the controller factory to get the requested controller
{
var factory = ControllerBuilder.Current.GetControllerFactory();
ControllerBase controller = (ControllerBase)factory.CreateController(
htmlHelper.ViewContext.RequestContext, controllerName);
controllerContext = new ControllerContext(
htmlHelper.ViewContext.RequestContext, controller);
}
Type controllerType = controllerContext.Controller.GetType();
ControllerDescriptor controllerDescriptor = new ReflectedControllerDescriptor(controllerType);
ActionDescriptor actionDescriptor = controllerDescriptor.FindAction(controllerContext, actionName);
if (actionDescriptor == null)
return false;
FilterInfo filters = new FilterInfo(FilterProviders.Providers.GetFilters(
controllerContext, actionDescriptor));
AuthorizationContext authContext = new AuthorizationContext(controllerContext, actionDescriptor);
foreach (IAuthorizationFilter authFilter in filters.AuthorizationFilters)
{
authFilter.OnAuthorization(authContext);
if (authContext.Result != null)
return false;
}
return true;
}
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