Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Security in MVC Views

In my MVC application I have a few different roles: Admin, General User, etc., etc.

I know that I can apply security to my Controllers via the Authorize attribute:

[Authorize(Roles="Admin")]
public ActionResult Create()
{
    return View();
}

But I also need to apply some security to the Views to not display certain sections of the View to certain roles:

@if( User.IsInRole("Admin") )
{
    @Html.ActionLink("Create", "Create")
}

Is it better to do it the above way, or handle this sort of security in a ViewModel:

public ActionResult Index()
{
    var model = new IndexViewModel();

    model.CanCreate = User.IsInRole("Admin");

    return View(model);
}

View:
@( Model.CanCreate )
{
    @Html.ActionLink("Create", "Create")
}

Does the second method have any benefits compared to the first or is it just a preference thing?

like image 784
Dismissile Avatar asked Oct 20 '11 17:10

Dismissile


3 Answers

The second way is more preferred, as your business logic will stay at model level.

In your example, business logic is very simple. However, imagine that requirements have changed and now not only Admins can create content, but also General Users that signed up more than 1 month ago. With business logic in view you'd have to update all your views.

like image 118
Sergey Sirotkin Avatar answered Dec 04 '22 23:12

Sergey Sirotkin


One way I have done this before is creating an action filter that inherits from the AuthorizeAttribute. The filter can be called something like DisplayIfAuthorizedAttribute, and in addition to the standard AuthorizeAttribute properties, has a property called ViewNameIfNotAuthorized.

The attribute calls the base method to do authorization, and if it fails, returns the ViewNameIfNotAuthorized view. Otherwise, it allows the action method to proceed normally.

You would then render these partial views via action methods, and call the action methods through Html.RenderAction or Html.Action in your parent view. Those action methods would be decorated with the attribute.

You now have a standardized way to do this and no authorization code polluting the internals of your action methods.

This is what the filter would look like:

public class DisplayIfAuthorizedAttribute : System.Web.Mvc.AuthorizeAttribute
{
    private string _ViewNameIfNotAuthorized;
    public DisplayIfAuthorizedAttribute(string viewNameIfNotAuthorized = null)
    {
        _ViewNameIfNotAuthorized = viewNameIfNotAuthorized;
    }
    public override void OnAuthorization(AuthorizationContext filterContext)
    {
        bool isAuthorized = base.AuthorizeCore(filterContext.HttpContext);

        if (!isAuthorized)
        {
            filterContext.Result = GetFailedResult();
        }
    }

    private ActionResult GetFailedResult()
    {
        if (!String.IsNullOrEmpty(_ViewNameIfNotAuthorized))
        {
            return new ViewResult { ViewName = _ViewNameIfNotAuthorized };
        }
        else
            return new EmptyResult();
    }
}

Your action method would be decorate as:

[DisplayIfAuthorized("EmptyView", Roles="Admin")]
        public ViewResult CreateLink()
        {
            return View("CreateLink");
        }
like image 36
Oved D Avatar answered Dec 04 '22 23:12

Oved D


You may need both...

Note that the 2nd one alone would not be secure, a user might be able to construct the URL for the actionlink in the browsers addressbar. So you absolutely need the attribute for security.

The second one is more a matter of user-friendliness or UI design. Maybe you want the user to be able to click Create and then have a choice to login differently.

like image 22
Henk Holterman Avatar answered Dec 04 '22 23:12

Henk Holterman