3

I'm creating an ASP.Net MVC 5 application. In my website, 3 different types of users exist.

  • Admin
  • Normal users
  • Restaurants

Each of these users have its own capabilities and access rights. Meaning, the view for each of them should be different.

I have created the models for both of the normal and restaurant. I was wondering how I can modify my existing structure to support this functionality.

public class User : IUser
{
    public User()
        : this(String.Empty)
    {
    }

    public User(string userName)
    {
        UserName = userName;
        Id = Guid.NewGuid().ToString();
    }

    [Key]
    public string Id { get; set; }

    [Required]
    public string UserName { get; set; }

    [Required]
    public string FirstName { get; set; }

    [Required]
    public string LastName { get; set; }

    public string Phone { get; set; }
    public string MobilePhone { get; set; }

    [Required]
    [DataType(DataType.EmailAddress)]
    public string Email { get; set; }

    public virtual IList<UserAddress> Addresses { get; set; }
}

public class Restaurant
{
    [Key]
    public int ID { get; set; }

    [Required]
    public string Name { get; set; }

    public virtual IList<RestaurantAddress> Addresses { get; set; }

    public virtual IList<RestaurantFood> Menu { get; set; }

    public virtual IList<Review> Reviews { get; set; }

    [DataType(DataType.Url)]
    public string Website { get; set; }

    [DataType(DataType.PhoneNumber)]
    public string Phone { get; set; }

    [DataType(DataType.PhoneNumber)]
    public string Fax { get; set; }

    [DataType(DataType.EmailAddress)]
    public string Email { get; set; }

    public int Seats { get; set; }

    public double AverageRating { get; set; }
    public double AveragePrice { get; set; }
}
Alireza Noori
  • 14,961
  • 30
  • 95
  • 179
  • [this](http://www.dotnettips.info/post/1166/%D9%85%D8%AF%DB%8C%D8%B1%DB%8C%D8%AA-%D8%B3%D9%81%D8%A7%D8%B1%D8%B4%DB%8C-%D8%B3%D8%B7%D9%88%D8%AD-%D8%AF%D8%B3%D8%AA%D8%B1%D8%B3%DB%8C-%DA%A9%D8%A7%D8%B1%D8%A8%D8%B1%D8%A7%D9%86-%D8%AF%D8%B1-mvc) post can be helpful – Sirwan Afifi Aug 17 '13 at 09:15
  • @SirwanAfifi Thanks. It was helpful to some extent. I'll have to look for some more. My problem is this: what is the best way to change the existing models to add support for this flexibility. Should I add all the info to the `User` model? Should I add the foreign key to the `User` model? I want to integrate the additional info in the model. – Alireza Noori Aug 17 '13 at 09:23
  • @AlirezaNoori I have updated my answer, which can give you exact details as to how to go about implementing it. You don't necessarily need ASP Security Kit, if you can spend lots of hours to figure out the implementation. – Varun K Aug 17 '13 at 09:41

3 Answers3

3

I'm not sure that I've got your Q correctly, But if you are using internet application template, you can simply manage access controls of your app using role management.

First of all, add some roles to the webpages_Roles table of your db.

Then, simply add users to those roles:

Role.AddUserToRole("role1");

Now, for filtering contents, you just need to do two jobs:

1) filter controller request to appropriate roles by use of [Authorize] attrib:

[Authorize(Roles = "role1, role2, ...")]

2) Render the appropriate content to the relative user. First retrieve the roles of the current user:

var roles = Roles.GetRolesForUser(User.Identity.Name);

Then, according to his/her roles, Render contents for him/her:

bool hasRole1 = roles.Contain("role1") | roles.Contain("admin");
// ...
@if (hasRole1)
{
    // Show content for role1 users...
}
Amin Saqi
  • 18,549
  • 7
  • 50
  • 70
  • Thank you very much. Although most people pointed me in this direction, to get the codes you mentioned above I had to read a couple of samples. I wish you posted this earlier. Nonetheless I accept this as the clear answer. – Alireza Noori Aug 21 '13 at 11:33
  • @AlirezaNoori - It's a great pleasure to be helpful – Amin Saqi Aug 21 '13 at 17:13
  • @AminSaghi Can we use the same thing with our custom tables (or not using the 'webpages_Roles' table) – kbvishnu Aug 22 '13 at 04:22
  • @VeeKayBee - Yeah, everything is possible! However, it's not a simple job so that I never try to go through it at all...!!! If you want your own fully customized approach, you should configure your membership provider and role provider. I just know that you perform those configuration in we.config file, but I doesn't know anything about how to do that... – Amin Saqi Aug 22 '13 at 07:14
  • @AminSaghi very Thanks for your comments When I was implementing the user authorization, we tried many approaches and we decided to create a mechanism of our own in order to incorporate the modifications from client in future. So I believe, there is a limit for our customization and after 2 or 3 years in production, you need to re-build the entire structure, if the client is required which is not handled by the current approach – kbvishnu Aug 22 '13 at 08:59
2

Authorization can be done based on user roles.

While creating authorization, we always keep in mind that it should dynamic. New user group will come having different permissions. So what I am suggesting is to have the information in a database.

For eg

User Group Admin Normal Users Resturants

Roles All Privileage Basic Privilage Intermediate Privileage

You need to use action filters to obtain this. http://msdn.microsoft.com/en-us/library/dd410209(v=vs.100).aspx

Next we need to assign privilages to each roles

All Privileage - addUser, addResturant, etc (you can use friendly names for administrative purpose. It can be displayed in UI, but we need to store controller name and action name.In case of addUser , friendly name will be Add User and we store like below

ActionsTable (actionId, friendName, Controller, Action)
1 -Add User - Users - Add 

RolesActionMapTable (roleId, actionID)
1-1

RolesTable (RoleId,Role Name,Desc)
1-AllPrivileage

GroupsTable (GroupId, GroupName)
1-Admin

GroupRoleMap (groupId, roleID)
1-1

Create a custom Autorize attriute by inheriting authorize attribute and apply it as filter for all methods. There is an overloaded function, and you can check the user is allowed to access that action there. Hence you can block the unauthorized access.

EDIT

From the route data we can identify the controller and action, so we can query db using the userID, controller and action that whether is allowed or you can get the users group and check that it was included the permission to access this

EDIT 2

public class CustomAuthorizeAttribute: AuthorizeAttribute
{
   protected virtual bool AuthorizeCore(
    HttpContextBase httpContext)
 {
   // 1.Httpcontext can gives you the controller and action
   // 2. retrive the group of user and check the user is allowed to execute this action
   // 3. if allowed, then return true else return false.
   // 4. You can redirect to another page saying you are not allowed to access this action
  }
)
}


//In controller
public class EmployeeController: Controller {

 [CustomAuthorize]
  public Create()
   {
   }

}

Hope this helps

kbvishnu
  • 14,760
  • 19
  • 71
  • 101
  • Thanks. I'm a little confused now :D Is there a tutorial with code samples to help me? – Alireza Noori Aug 17 '13 at 09:07
  • 1
    I have the same situation one year back. I am not in position to share the code and let me search some tutorials http://stackoverflow.com/questions/11829937/how-to-show-or-hide-controls-based-on-roles-asp-net-mvc-4-razor – kbvishnu Aug 17 '13 at 09:16
  • Thank you very much. Could you please kindly help me to update my models? I want to have a user to have the basic information and based on the user type, get the extended info for him/her. Should I use: `public virtual string Reestaurant ID { get; set; }` or `public virtual Restaurant Restaurant { get; set; }` – Alireza Noori Aug 17 '13 at 10:30
  • For better solutions you need to ask as another question. Also if you feels I helped you please accept as answer. – kbvishnu Aug 17 '13 at 10:33
  • I kept the question open for other users to see it. Thanks. – Alireza Noori Aug 17 '13 at 12:05
0

To achieve this in a scalable fashion with granular control you need permission-based authorization. You can try something like ASP Security Kit. ASP Security Kit is built from ground up to build systems like this.

Edit: This is how it can work:

  1. You define a unique permission code with every action method. For example, CreateRestaurant, ReserveRestaurant
  2. These permission codes are stored in a master Permissions table in the database.
  3. You can create a seperate roles table and associate permissions appropriately. However, ASP Security Kit introduces a new concept of implied permissions so you don't need role as a separate construct; you just create a higher-level permission, for example, 'RestaurantOwner', and make other permissions implied by it.
  4. There's a UserPermit table which associates permissions with users. For a specific type of users, E.G. restaurant owner, you will assign applicable permissions as the user is created.
  5. As user logs in, you load his permissions in the memory.
  6. You need a mechanism by which each controller's action is executed only if user possesses the unique permission code associated with that action. If user does not, you'll redirect him to a default page with message stating "unauthorized action"
  7. You can also look into the user permissions loaded to display or hide menu options.

ASP Security Kit does most of the above for you; for example, it can automatically infer permission code for authorization so you don't have to hard code it. In addition, you need resource checks so that different users and restaurant owners do not fiddle with each other data.

Disclosure: I'm the creator of ASP Security Kit.

Varun K
  • 3,593
  • 2
  • 25
  • 26