2

Situation: I´m securing my actions using the AuthorizeAttribute of MVC. I´m having several UI-components containing functionalities like INSERT, DELETE, ... which are resulting in an action if the end-user of the appliation clicks e.g. a button. Only those buttons should be visible to the user which he is allowed to execute. To avoid placing the permission for user-actions at least two times (button and controller-action) I`m thinking about that the button could determine the AuthorizeAttribute of controller and/or action to control its visibility. General: The application has multiple areas and controllers.

I found this answer (Accessing the list of Controllers/Actions in an ASP.NET MVC application) which indicates that the class ReflectedControllerDescriptor could help.

Is there a way to determine from the url the area and controller and action regarding to the existing routes within the mvc-application?

An example:

I have got a view: /shop/products/all

This view contains two links - /shop/user/recommend - /system/users/loggedon

The actions "recommend" and "loggedon" are decoreated with the Authorize-attribute and these links should be only visible if the user is allowed to execute them. Therefore if possible I want to use the already attached attribute.

Community
  • 1
  • 1
xforfun
  • 592
  • 6
  • 19

1 Answers1

1

This is how I did it.

I have updated the answer. it is for mvc3.

public class MyActionAttribute : ActionFilterAttribute
{
    private readonly string _conroller;
    private readonly string _action;
    private readonly string _id;

    public class MyActionAttribute : ActionFilterAttribute
    {
    public bool IsAllowed(string _conroller, string _action, string _id)
    {
        //write your logic to check if a user is allowed to perform the given action on this controller,action and id
        return UserisAllowed(_conroller, _action, _id);
    }

     public override void OnActionExecuting(ActionExecutingContext filterContext)
    {

        var area =filterContext.RouteData.DataTokens["area"];

        if (!IsAllowed(filterContext.ActionDescriptor.ControllerDescriptor.ControllerName, filterContext.ActionDescriptor.ActionName, filterContext.RouteData.DataTokens["id"].ToString()))
        {
            //send user to somewhere saying you are not allow
            return;
        }

        base.OnActionExecuting(filterContext);
    }
}

Now Apply this attribute to the controller action.

    [MyAction]
    public ActionResult Someview()
    {
         return View();
    }

For the link you can check this way

 if (new MyActionAttribute().IsAllowed("yourcontroller","youraction","id"))
    {
          Html.ActionLink(whatever)
    }

I hope this gives you start. This way your logic remains at one place and can be used for edit/delete type links and also for the controller.

Parminder
  • 3,088
  • 6
  • 37
  • 61
  • So far sound logic - concerning that line and assuming there are areas: "return UserisAllowed(_conroller, _action, _id);" How can I determine the controller of the area to see if the action is decorated by the attribute? – xforfun Feb 19 '14 at 12:07
  • i think you can get it by saying actionContext.RouteData.Values["area"]; I havent tested it. – Parminder Feb 19 '14 at 13:55
  • I want to access it when the action is not executed. "OnActionExecuting" in your code is called if the action is executed. But in my case I´m referring to a non-executed action. – xforfun Feb 19 '14 at 14:04
  • what do you mean by non-executed action. I am just answering how to write your logic once and use it twice. – Parminder Feb 19 '14 at 14:09
  • Example: The attribute is assigned to action A which returns view VA. User opens action B with view VB and now I want to decide if the link is shown which refers to A and VA. How can I get the attribute of A? I know A's area and A's controller in B as strings... A is not executed but I want to get the definition. – xforfun Feb 19 '14 at 14:13