10

I am trying to build a dynamic menu for my ASP.NET MVC4 web application. As I am constructing the menu I want to make sure that menu items for which a user should not have access are not displayed in the menu.

I am using forms authentication and the [Authorize] attribute with each page requiring a given a role.

Given two strings (Controller and Action), and a logged in user, how can I determine if a user will have access to that Controller Action?


All of my menu data is stored in a database. My plan to render the menu is to construct a JSON object of the menu data and embed that into the View. Then client side I will use Handlebars.js and plug the menu JSON object into a template.


What I am trying to do is check permissions on a given Controller/Action for a user as I am rendering the menu data. My initial thought was to use reflection and look up the controller action method and check for the existence of an Authorize attribute and check to see if the current logged in user has the necessary role access that page. If not, then the menu item would not be rendered.

I am always reluctant to use reflection however, there usually tends to be an easier way of doing things.

Tirthak Shah
  • 515
  • 2
  • 11
jdavis
  • 8,255
  • 14
  • 54
  • 62
  • How are you rendering the menu? Is it part of the view proper, or do you have some sort of subview, like a RenderControl or RenderAction method? Also, you appear to be asking two questions. Do you want to hide/show menu items based on security, or have you already figured that part out? – Robert Harvey Jan 17 '13 at 15:28
  • For hiding/showing menu items, there might be some help here: http://stackoverflow.com/questions/8411224/asp-net-mvc-hide-show-menu-items-based-on-security – Robert Harvey Jan 17 '13 at 15:29
  • 2
    You have to build your claims and check if user has the claim. Best way to accomplish security is not role-based (good for menus, though) but action-based security. – T.S. Jan 17 '13 at 15:30
  • You can use MvcSiteMapProvider to generate the menu. – Joe Feb 17 '14 at 08:11

7 Answers7

1
public static IEnumerable<MethodInfo> GetActions(string controller, string action)
{
    return Assembly.GetExecutingAssembly().GetTypes()
           .Where(t =>(t.Name == controller && typeof(Controller).IsAssignableFrom(t)))
           .SelectMany(
                type =>
                type.GetMethods(BindingFlags.Public | BindingFlags.Instance)
                    .Where(a => a.Name == action && a.ReturnType == typeof(ActionResult))
             );

}

then

var roles = ((AuthorizeAttribute) (GetActions("ControllerName" + "Controller", "ActionName").First().GetCustomAttributes(typeof (AuthorizeAttribute), false)[0])).Roles;
if(roles.Contains("admin or smth"))
{
        doSomsing();
}
user355308
  • 539
  • 4
  • 10
  • this solution only take into account the AuthorizeAttribute upon the action, but not the AuthorizeAttribute define upon the controller – amichai May 24 '21 at 08:14
0

I have implemented a very similar scenario. The only difference is that my menus are stored in XML files.

Since you have your menu data stored in a database, I suggest you either add an xml field that contains security info to each menu record; or, have a new table that maps menu items to users. The table can look like this:

MenuItemName (id)             User
---------------------------------------
ViewVacationHistory (12)      firstuser
ViewVacationHistory (12)      seconduser
ApproveVacationRequest (10)   seconduser

Now when your controller receives the request that would result in displaying menu items, and since your controller is decorated with the Authorize attribute, it will receive the user in the HttpContext. Here you simply query the database for menu items that match, then render the menu accordingly.

gush
  • 1
  • 3
0

Use ActionFilter Attribute to filter the users based on Role http://www.asp.net/mvc/tutorials/hands-on-labs/aspnet-mvc-4-custom-action-filters

Mano1822
  • 61
  • 1
  • 7
0

create the class called Rolevalidation and add the code as below

public class AuthorizeRoles : AuthorizeAttribute
{
    List<string> roles = new List<string>(“your list of roles”);
    bool isAuthenticated = false;
    for (int i = 0; i < roles.Count(); i++)
    {
        if (u.Role.Name == roles[i])
        {
            isAuthenticated = true;
            break;
        }
    }


    if (isAuthenticated)
    {
        SetCachePolicy(filterContext);
    }
    else
    {
        filterContext.Result = new RedirectResult("~/Error");
    }
}

Add this code in every controller’s begining* [AuthorizeRoles(Roles = "SuperAdmin")]

vrajs5
  • 4,066
  • 1
  • 27
  • 44
user3217843
  • 424
  • 1
  • 3
  • 17
0

The links will be generated by the json object which comes from an action and controller.

The json object should have a list of links(or what ever required to implement the menu item), the list should be generated by sort of settings stored in the database, tells each user what links to show.

Beside that what if the user has the URL so in this case you need to use

https://msdn.microsoft.com/en-us/library/system.web.mvc.authorizeattribute.users(v=vs.118).aspx

Mahmoud Hboubati
  • 1,007
  • 11
  • 26
0

Assuming you have a view that contains all the menu html code, probably will be better just using:

<ul class="menu">
    <li>
        @Html.ActionLink("Home", "Index", "Home")
    </li>
    @if (System.Web.Security.Roles.IsUserInRole(User.Identity.Name, "Administrator"))
    {
        <li>
            @Html.ActionLink("Statistics", "Index", "Stats")
        </li>
    }
</ul>

Hope this helps!

Edgardo
  • 29
  • 4
-1

You can use an Authorize attribute with which to decorate an action from the controller [Authorize(AuthorizationContext)] or you can extend the authorize attribute for custom authorization;

You can also define some conventions in a dictionary in which you define that a Create action of a controller needs a create type authorization a.s.o.

Dictionary<string, Right> actionConventions = new Dictionary<string, Right>
    {
        { "Index", Right.View },
        { "List", Right.View },
        { "Open", Right.View },
        { "Create", Right.Create},
        { "Edit", Right.Edit },
        { "Delete", Right.Delete }
}

and override OnAuthorization and Authorize methods of AuthorizeAttribute and either check the convention if the action sticks to the conventions defined in the dictionary or check a specific condition where you either Authorize(AuthorizationContext) for the action or HandleUnauthorizedRequest(AuthorizationContext).

Handling the menu you can create an authorization service in which you return the rights of the current user and add a class containing the rights of the user and you check the Model when rendering the model, if a menu item should be rendered or not.

Authorize Attribute MSDN

TigOldBitties
  • 1,331
  • 9
  • 15