Example
User "jtirado" is assigned role "HR-Assistant", can access route "mymvcapp/employeee/edit/1452" to edit employee (id:1452) data.
Being "HR-Assistant", this user can change employee telephone number and e-mail, can view employee salary but not edit the amount.
Telephone number, email, salary are dabatase fields and are represented/rendered by a "asp.net-mvc-control" or "HTML-control" on the View. So I want to restrict access to these controls based on user's role.
Previous experience
I've done this before for a classic 3-tier ASP.Net 3.5 web forms application, using a MasterPage, a BasePage class and a RoleBasedAccessControl database model.
MasterPage builds the options menu the user has access according to his assigned role.
BasePage class checks if the user has access to the required page, and if so, checks which controls (ex: DdlClientType, TxtLastName,ChkIsActive) the user can edit.
This way, I don't have to use if-then sentences to check permissions and, I can create as many roles as I want, giving them any permissions, without having to change any C# code.
I'm planning to use the same RoleBasedAccessControl database model for this new MVC app.
Problem
So my dubts are about how to implement the MasterPage and BasePage class using ASP.Net MVC 3 or if there's another way of achieving this, and if I should do it other way.
It seems to me that ViewMasterPage is the MVC-equivalent to Web-Forms-MasterPages. I've also heard about Razor layout pages.
Anyway, I suppose I should handle all of this in a Controller.
I will be using:
- ASP.NET MVC 3.0
- Razor
I've checked these posts:
asp.net mvc user permissions and views
Best Practices for controlling access to form fields
Best practices for control permissions?
Implement secure ASP.NET MVC applications
But they don't fully fit my case.
It sounds like you could use a custom editor template, and have your logic in there.
In your Viewmodel, you can use attributes to determine which template will get used - either with UIHint, or by setting the DataType attribute and having your custom template for that.
Then your editor template can determine whether to render the edit or display value (or hide it entirely). Don't forget to enforce the same rules in your binders, or you open up the possibility of having users manipulate data that they should not have access to.
One issue with the Razor engine is that there is no "Controls" collection on a page, as there is in WebForms. Thus you wouldn't be able to iterate through all of the controls in a page and do something with them.
That said, you can still use a "Base View" idea by subclassing
System.Web.Mvc.WebViewPage
and/orSystem.Web.Mvc.WebViewPage<TModel>
as outlined in a previous question. Likewise, inheriting from Controller will help for a base controller as well.I'm not sure I have a concrete answer here, but one thing I've done is add custom attributes on my model properties indicating which roles can access them. Then I overload the built-in methods like
@Html.TextBoxFor()
, passing in the current user's roles. In the overload I check the roles argument against the attribute on the property.In your case, attributes may not work, and instead you'll read the authorization from a database; same idea, just a different implementation.
Hope that gets you going in the right direction.