David Lay
David Lay

Reputation: 2955

How to keep views free of authorization logic in mvc?

I have a view to display a list of items. The user can edit, delete or create new items, but according to their authorizations they may or may not be allowed to do some of this actions.

I have the requirement to display only the actions which the current user is allowed to do, but I don't want to clutter the views with authorization if-else's

Despise of being a very common requirement, I can't find a real satisfactory way of doing it.

My best approach so far is to provide an overload to the Html.ActionLink extension method that takes the permission to ask for, but there are going to be more complex scenarios, like hiding entire blocks of html or switching a textbox for a label+hidden.

Is there a better way to do this?

Upvotes: 5

Views: 573

Answers (5)

Sebastien Martin
Sebastien Martin

Reputation: 1379

I personally don't see anything wrong with this kind of conditional logic within the view. The logic is still all about presentation. You decide whether to show or hide, enable or disable, highlight etc. This is the view's job, not the controller's. As long as the view does not need to actually compute anything to come to its decision. The controller should be agnostic of the view's implementation as much as the other way around.

My approach would be this:

  • Make the controller do the actual logic of deciding the level of access that the user has
  • Pass this information to the view using (ie via the ViewModel) but in a way that is neutral to implementation details (ie "user is admin", "user is an author", etc)
  • Let the view draw itself appropriately using only the pre-compiled data that is provided by the controller.

This also has the benefit that the view itself can be removed and replaced without any effect on the controller.

Upvotes: 1

dariol
dariol

Reputation: 1979

In complicated situations where are many conditions and rules I'm doing this that way:

ViewModel

public class ModelView
{
    private IAuthorisationService { get; set; }

    public bool CanShow
    {
        ...
    }
}

View:

<% if(Model.CanShow) { %>
    <html>
<% } %>

Upvotes: 0

krisg
krisg

Reputation: 806

Would it not be simpler to create several views with various controls based on what values the user can change, then return the right view based on the user's access rights?

Views should be for presenting information only, there really shouldn't be any conditional logic contained in them, or at least a bare minimum.

I've always found when i get to the point where i'm finding it hard to grok a situation like yours, the best solution is always to go back to the controller and e-assess what i'm passing to the view in the first place.

By the time the View is called to do its job, all of the important 'decisions' should have already been made.

Upvotes: 0

Tejs
Tejs

Reputation: 41236

One example I can think of would be to invoke Html.RenderAction (link: http://msdn.microsoft.com/en-us/library/ee703490.aspx), and then pass the link you wish to use as a route value to the action method (it will appear as a parameter on your action). Because it's a RenderAction, you get to go back through the controller process and thus you can have it render whatever view or data you want depending on the user's state.

Example:

<% Html.RenderAction("Permissions" /* Controller */, "PermissionLink", new { Url = "Admin.aspx" }); %>

And your controller would have something like:

public ActionResult PermissionsLink (string url)
{
     // Do Whatever kind of Authentication you want here, Session is available, etc

     if(authenticated)
        return View("Link");
     else
        return View("Blank");
}

Upvotes: 2

Raj Kaimal
Raj Kaimal

Reputation: 8304

We had this same issue. We ended up writing a lot of helper methods and in cases where lots of html output was required, we put them in partial views.

Upvotes: 0

Related Questions