1

I wish to implement a role based operations restrictions in my site. For example, I wish to restrict the ability to edit a post only by the post author or a set of groups.

I do know that I can write something like:

     if (User.IsInRole("Admin"))
          return true;
     return post.Author.AccountId == currentAccountId;

but my wondering is if I can do it dynamically without using a fixed name of roles. I wish to create a control panel, that enables the admin to add new roles. In each role creation/modification form, there's a checkbox that says "Can edit other posts?". Based on that value I'll take action in the method above. I've done that many times in PHP, but since it's my first ASP.NET MVC site I'm wondering if it's possible using the default SQL database structure (using MVC4 with the new SimpleMembershipProvider, but I don't mind to write a custom provider if I have to).

I've read about the new Claims feature, but I didn't saw a way that I can use it in this case, am I right?

I've looked at the net but didn't find anything...

Any suggestion is very welcome! Thanks!

2 Answers 2

3

Yes, you can do some custom autorization with the Forms Authentication but you will need to do some customizations.

First of all, you have to customize your AuthenticateRequest event of your application to work with roles, so, on your Global.asax you have to set a code to customize it to the current user:

protected void Application_AuthenticateRequest(object sender, EventArgs e)
{
    if (HttpContext.Current.User != null)
        if (HttpContext.Current.User.Identity.IsAuthenticated)
            if (HttpContext.Current.User.Identity is FormsIdentity)
            {
                var id = (FormsIdentity)HttpContext.Current.User.Identity;
                var ticket = id.Ticket;

                // Get the stored user-data, in this case, our roles
                string userData = ticket.UserData;
                string[] roles = userData.Split(',');
                HttpContext.Current.User = new GenericPrincipal(id, roles);
            }
}

When you authenticate the user you have to set the role, so on your controller you have to have a post action to authentication with a code like this:

if (LoginService.Validate(userame, password) 
{
   FormsAuthentication.Initialize();

   var ticket = new FormsAuthenticationTicket(1,
                                 username, //user
                                 DateTime.Now, //begin
                                 DateTime.Now.AddHours(3), //timeout
                                 false, //remember?
                                 permission, // permission.. "admin" or for more than one  "admin,marketing,sales"
                                 FormsAuthentication.FormsCookiePath);

  var cookie = new HttpCookie(FormsAuthentication.FormsCookieName,   FormsAuthentication.Encrypt(ticket));

  if (ticket.IsPersistent) cookie.Expires = ticket.Expiration;

  HttpContext.Current.Response.Cookies.Add(cookie);
}

After that, you will be able to use a code like your post:

if (User.IsInRole("Admin"))
{ /** do something / }

Or

if (User.IsInRole("Admin") || (User.IsInRole("Marketing") && User.IsInRole("Sales")))
{ /** do something / }

You also can check the role on the Authorize attribute of asp.net mvc:

[Authorize(Roles = "Admin")]
public class CompanyController : Controller
{
   // actions
}

Edits

You could have a table to associate a permission "Admin" with some privileges (edit comments, delete comments, etc... that could be stored in a table on database). Try something like this to implement a custom check permission:

public static class UserExtension
{
    private static bool RoleHasPrivilege(string role, int privilege)
    {
        // performe a database/cache access to check if the role has the privilege
    }
    public static bool IsInRole(this IPrincipal user, string role, int privilege)
    {
        // check if the user authenticate has the "role" permission and the privilege is associate with this role...
        return user.IsInRole(role) && RoleHasPrivilege(role, privilege);
    }
}

And you could use:

if (User.IsInRole("Admin", 1)) 
{
  // "Admins" has access
  // 1 - can edit posts... for sample
}
Sign up to request clarification or add additional context in comments.

4 Comments

Thanks for the detailed answer!I'm familiar with that concepts and in order to store some additional information I did implemented a custom Identity. My question is how can I create a settings for each role I'm creating, so that for instance "Admin" can "access the admin control panel", "edit others posts", "remove other posts" etc. without hand-code it.
In this case you could create your own method to check it using the Roles and some information persisted at your database. It's more a question about modeling data than an mvc structure. Look my edits how could you implement it.
I thought that MVC has this feature built-in, but your answer provides me a starting point. Thanks! :)
User.IsInRole("Admin") not working !!!! in MVC4. I do everything as suggested but not luck. Help please
0

Somehow solution suggested by Felipe Oriani is not working

When implemented in global.asax and uses method

User.IsInRole("Admin")

it always return false. So I figure out another solution to implement in a custom AuthorizeAttribute.

public class AuthenticateRequestAttribute : AuthorizeAttribute
{
    protected override bool AuthorizeCore(HttpContextBase httpContext)
    {
        HttpContextBase context = httpContext;

    if (context.User != null)
        if (context.User.Identity.IsAuthenticated)
            if (context.User.Identity is FormsIdentity)
            {
                FormsIdentity id = (FormsIdentity)context.User.Identity;
                FormsAuthenticationTicket ticket = id.Ticket;

                string userData = ticket.UserData;
                string[] roles = userData.Split(',');
                context.User = new GenericPrincipal(id, roles);
            }
    return base.AuthorizeCore(httpContext);
}

}

You can use this custom attribute in place of built in [Authorize] attribute

[AuthenticateRequest]
public class AuthorizedController: Controller
{

}

Then you can definitely use

if (User.IsInRole("Admin"))
{ /** do something / }

Hope this helps

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.