2

I thought this would be very simple but I'm struggling a little. I'm working on a project for a client using MVC 3 that requires users to agree to certain conditions before using the site. I have created a standard agree/disagree screen which is loaded when first coming into the site, but if a user types a address to a different part of the site they can bypass the conditions for example www.test.com loads the conditions but if the user types www.test.com/home they bypass the conditions.

How can I make sure they have agreed to the conditions before they can get anywhere else on the site? I have been trying a session variable, which I think is the way to go, but is there a way to check this variable on every page request without having to write a check into every Controller Action on the site?

tereško
  • 58,060
  • 25
  • 98
  • 150
Chris Sainty
  • 7,861
  • 2
  • 37
  • 59

2 Answers2

7

You could make a custom attribute and add it to the top of the Controller.

For example:

    [AgreedToDisclaimer]
    public ActionResult LoadPage()
    {
         return View();
    }

Which would only load the view if the AgreedToDisclaimer returns true.

public class AgreedToDisclaimerAttribute : AuthorizeAttribute
{

    protected override bool AuthorizeCore(HttpContextBase httpContext)
    {
       if (httpContext == null)
        throw new ArgumentNullException("httpContext");

       // logic to check if they have agreed to disclaimer (cookie, session, database)
       return true;
    }

   protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
   {
          // Returns HTTP 401 by default - see HttpUnauthorizedResult.cs.
           filterContext.Result = new RedirectToRouteResult(
            new RouteValueDictionary 
            {
             { "action", "ActionName" },
             { "controller", "ControllerName" },
             { "parameterName", "parameterValue" }
            });
   }
}

http://msdn.microsoft.com/en-us/library/dd410209(v=vs.90).aspx

http://msdn.microsoft.com/en-us/library/system.web.mvc.authorizeattribute.handleunauthorizedrequest.aspx

Darren
  • 68,902
  • 24
  • 138
  • 144
  • Thanks Darren that should do what I'm after although if they have not viewed the disclaimer then I need to redirect them to the disclaimer. With what you've suggested all I do is redirect them to a login screen, is it possible to redirect to another URL? – Chris Sainty Aug 15 '12 at 11:36
  • 1
    Yeah you can use the HandleAuthorisedRequest to redirect to the Disclaimer. I will update my answer. – Darren Aug 15 '12 at 11:48
1

There are two approaches for the issue:

  • If this condition alter the site (like StackOverflow's notifications, that show at the top), but do not prevent you from using it, then I think it should be solved in presentation logic ( thus in the view, if you have real view an not just glorified template ).

    Session variable in this case is just another part of model layer's state. When view instance requests data from the model layer, it is informed, that there is new notification for the user. This would mean that each view would have an ability to add representation of this notification to the current response. Preferably, by choosing to use one additional template, when assembling the output. This functionality would be shared between all views and thus could be implemented in base class, providing one single point of change.

  • If this acceptance of disclaimer is mandatory for everyone (like "I am 18 or older" in adult-themed sites), then the best option, in this case, would be to check, if user has agreed to condition in the routing mechanism. I am not sure how much control you have over request routing in ASP.NET MVC, but that again would provide you with as single point of change.

    If decision is made in routing mechanism, it would also mean, that you put the condition outside the standard MVC triad entirely.

tereško
  • 58,060
  • 25
  • 98
  • 150