1

I am creating an ASP.NET MVC application and this is my problem:

When accesing an action in controller, beside checking if logged user in in allowed role with Authorize attribute, i need to include logic conserning if user i want to edit(it's id comes as a parameter of action) has lower role than the logged user( i dont want to allow regular users to edit admins etc.)

Where should i implement this logic? I wanted to override methods in AuthorizeAttribute and simply add this logic there, but in that case i would have to send the user i want to edit in parameter of the attribute, but that is not allowed.

Another option would be to create private method in the controller, but if i want to use this logic in other controllers i would have to repeat this code again and again.

What is the right solution please?

[AttributeUsageAttribute( AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = true )]
public class AuthorizeRolesAttribute : AuthorizeAttribute
{
    private string _roles { get; set; }            
    private UserEntity _user { get; set; }
    private UserEntity _loggedUser { get; set; }

    public AuthorizeRolesAttribute(string Roles, string User, int Id)
    { 
        _user = new UserEntity();
        _loggedUser = new UserEntity();
        _roles = Roles;
    }

    //Called when access is denied
    protected override void HandleUnauthorizedRequest( AuthorizationContext filterContext )
    {                        
        filterContext.Result = new RedirectToRouteResult(
                new RouteValueDictionary( new { controller = "Account", action = "LogOn" } )
        );                 
    }

    //Core authentication, called before each action
    protected override bool AuthorizeCore( HttpContextBase httpContext )
    {            
        bool b = false;
        string[] roles = _roles.Split(',');
        //Is user logged in?
        if ( httpContext.User.Identity.IsAuthenticated )
        { 
            //If user is logged in and we need a custom check:
            if ( roles.Any(r => httpContext.User.IsInRole(r)) && HasPermission(_user, _loggedUser))
                b = true;
        }
        //Returns true or false, meaning allow or deny. False will call HandleUnauthorizedRequest above
        return b;
    }

    private bool HasPermission(UserEntity user, UserEntity loggedUser)
    {
        if (user.IsAdmin) return false;
        if (loggedUser.IsAdmin || loggedUser.IsApplicationAdmin) return true;                                   

        if (loggedUser.IsAmbassador)
        { 
            if (user.IsApplicationAdmin)
            { return false; }
            else
            { return true; }
        }
        return false;
    }
}

As you can see, at the moment im just creating empty fake objects _user and _loggedUser in constructor because i dont know how to pass them.

Martin
  • 404
  • 1
  • 5
  • 15

1 Answers1

1

As I understand it, you need to create your own Authorization attribute deriving from AuthorizeAttribute, so that you can implement these parameters you want, and then you can override the OnAuthorization method to implement your specific logic:

This is the method you have to override: http://msdn.microsoft.com/en-us/library/system.web.mvc.authorizeattribute.onauthorization(v=vs.118).aspx

Auternatively, you can implement an IAuthorizationFilter: http://msdn.microsoft.com/en-us/library/system.web.mvc.iauthorizationfilter(v=vs.118).aspx

And finally, you can register both AuthorizeAttributes and IAuthorizationFilters globally, so you don't have to place them on top of each action or controller: http://weblogs.asp.net/gunnarpeipman/asp-net-mvc-3-global-action-filters

Andre Pena
  • 56,650
  • 48
  • 196
  • 243
  • I know i should implement these, and i already did. But i need to hand an object of user, lets say UserEntity class. I know i cannot do that, so at least i want to hand email of user which is unique for my users. When i implement my custom attributes right, can i do something like this? [CustomAttribute(Roles = "admin, administrator"), Email = Model.UserToEdit]... i am pretty sure i cannot, i can only hardcode it like Email = abc@def.com... But i dont know what the email should be at that time – Martin Oct 30 '14 at 10:17