Alex Rivera | Logout

How to get custom annotation attributes for a controller action in ASP.NET MVC 4?

Asked 2012-11-02T18:45:57.633
10

I am working with a permission based authorization system for my app in ASP.NET MVC. For this I have created a custom authorization attribute

public class MyAuthorizationAttribute : AuthorizeAttribute
{
    string Roles {get; set;}
    string Permission {get; set;}
}

so that I can authorize a user by both role or a specific permission key with annotation for actions like

public class UserController : Controller
{
    [MyAuthorization(Roles="ADMIN", Permissions="USER_ADD")]
    public ActionResult Add()

    [MyAuthorization(Roles="ADMIN", Permissions="USER_EDIT")]
    public ActionResult Edit()

    [MyAuthorization(Roles="ADMIN", Permissions="USER_DELETE")]
    public ActionResult Delete()
}

then I override AuthorizeCore() method in MyAuthorizationAttribute class with similar logic(pseudo code)

protected override bool AuthorizeCore(HttpContextBase httpContext)
{
    if(user not authenticated)
        return false;

    if(user has any role of Roles)
        return true;

    if(user has any permission of Permissions)
        return true;

    return false;
}

Up to this is working fine.

Now I need some sort of extension methods so that I can dynamically generate action url in view pages that will return action url based on MyAuthorization attribute authorization logic for the given action. Like

@Url.MyAuthorizedAction("Add", "User")

will return url to "User/Add" if user has admin role or has permission of "USER_ADD" (as defined in attributes for the action) or return empty string otherwise.

But after searching in internet for few days I could not figure it out. :(

So far I have found only this "Security aware" action link? which works by executing all action filters for the action until it fails.

<
Edit
Report

1 Answer

0

My only recommendation would be to write an extensions methods on IPrincipal instead which would look like

public static bool HasRolesAndPermissions(this IPrincipal instance,
    string roles,
    string permissions,)
{
  if(user not authenticated)
    return false;

  if(user has any role of Roles)
    return true;

  if(user has any permission of Permissions)
    return true;

return false;
}

Then your code in the views/partials is a little more readable in terms of what it's actually doing (not doing anything with html, but validating a user) then the code in the views/partials looks like

@if (User.HasRolesAndPermissions(roles, permissions)) 
{ 
   @Html.ActionLink(..);
}

Each MVC Page has the property WebViewPage.User for the current user.

The problem with your purposed solution (and the link to security aware link) is that the creation of the link, and the Authorize on the controllers could be different (and mixing responsibilities in this type of fashion in MY opinion is bad practice). By extending IPrincipal a new authorization would look like:

protected override bool AuthorizeCore(HttpContextBase httpContext)
{
  return user.HasRolesAndPermissions(roles, permissions)
}

Now both your Authorize Attribute and Views use the same roles/permissions data logic.

answered 2012-11-02T20:11:38.883

Your Answer