What's the best practice for Field Level security in MVC 3
I'm building a MVC 3 application that will be used by several different groups. In my views, I'm using all of the HTML Helpers to build out my UIs. (e.g. Html.DropDownListFor(), Html.EditorFor(), etc.)
I need to implement different security based on that user's role. Let's use the example of a person:
I have a View that looks like this:
@Html.LabelFor(m=>m.FirstName): @Html.TextBoxFor(m=>m.FirstName) <br />
@Html.LabelFor(m=>m.LastName): @Html.TextBoxFor(m=>m.LastName) <br />
@Html.LabelFor(m=>m.IsActive): @Html.EditorFor(m=>m.IsActive)
The things that I need to accomplish are: 1. Prevent users who are not in the "Admin" role from editing any field. 2. Prevent users from editing the First/Last name fields if "IsActive" is false.
It seems like what I need is a way to inject behavior into the built-in helper functions. Either that, or write my own. There are some other questions out in StackOverflow talking about a database model for storing Security based on rol开发者_运维技巧es, but nothing to help with the middle-tier.
I'm trying to accomplish re-use of the same views. Do I really need multiple views?
Create a custom ModelMetaDataProvider. This will allow you to utilize a business rules engine or even a simple ACL implementation to modify the metadata for each model and it's properties before they ever make it to the view. Then the built in helpers will typically obey the metadata when rendering a field. For example it you make a field ShowForEdit = false because the current user has no access then the helper will not render the field.
This technique helps keep logic out of your view/presentation layer and your views nice and clean. In some cases you may need to build a custom template to further control the rendering of your controls based on the metadata but it's still cleaner than having a bunch of if statements in your view.
It's fairly easy.
@Html.LabelFor(m=>m.FirstName): @if(User.IsInRole("Administrator")) {Html.TextBoxFor(m=>m.FirstName)} else {Html.DisplayFor(m=>m.FirstName)} <br />
@Html.LabelFor(m=>m.LastName): @if(User.IsInRole("Administrator")) {@Html.TextBoxFor(m=>m.LastName)} else {Html.DisplayFor(m=>m.LastName)} <br />
@if(User.IsInRole("Administrator")) {
Html.LabelFor(m=>m.IsActive)<text>:</text> Html.EditorFor(m=>m.IsActive)
}
However, you can get into some trouble this way, because you have to be careful that your model does not contain Required fields that you hide from normal users.
It is better to use seperate ViewModels for admin/non-admin if that is the case. You will probably also do better if you use EditorTemplates as well.
精彩评论