views:

43

answers:

1

Consider the following code:

    [Authenticate(Order = 1)]
    public ActionResult SomeActionThatRequiresAuthentication()
    { 
        var model = new SomeViewModel(); 
        // Do something with an authenticated session/user...
        return View(model);
    }

Does the Authenticate attribute happen before or after the code inside the SomeActionThatRequiresAutehntication method is executed?

I am asking this because I have a Attribute that does something like this:

    public class Authenticate : CustomAuthorizeAttribute
{
    public override void OnAuthorization(AuthorizationContext filterContext)
    {
        if (!UserService.IsAuthenticated && !HttpContext.Current.Response.IsRequestBeingRedirected)
            HttpContext.Current.Response.Redirect(ViewUtil.Actions.User.LogOnUrl());
    }
}

As you can see the attribute will redirect a user if the user is not authenticated. However it appears that the redirect only happens after the action executes. This is causing problems because I made the assumption the user is authenticated when executing the action. First I need to understand if the attributes are supposed to happen before or after the action is executed, or am I thinking of the workflow completely wrong?

Thanks, Paul


After researching this some more it is clear that the filterContext.Result has to be set for this to work. After making a small change in my Authorize attribute, it is now working:

    public class Authenticate : CustomAuthorizeAttribute
{
    public override void OnAuthorization(AuthorizationContext filterContext)
    {
        if (!UserService.IsAuthenticated && !HttpContext.Current.Response.IsRequestBeingRedirected)
            filterContext.Result = new RedirectResult(ViewUtil.Actions.User.LogOnUrl());
    }
}
+3  A: 

You're correct, Attributes execute before the action in question, so [Authenticate] should most certainly execute first and, if the user is not authenticated, the Action code never executes until after the user is redirected, authenticates and is redirected back to this action.

Edit based on comment: the MVC Framework OnAuthorizatrion method (source here) doesn't redirect, but sets the filterContext.Result to a `HttpUnauthorizedResult()' (which just sets a 401 status code). That result causes the authentication module to redirect the user to the login page. Assuming that the rest of your custom implementation is standard (not overriden or calling the base methods) changing this

HttpContext.Current.Response.Redirect(ViewUtil.Actions.User.LogOnUrl()); 

to this (or something similar, as long as you set the Result)

filterContext.Result = new HttpUnauthorizedResult();

should do the trick, at at least get your further down the road.

Brandon Satrom
@Brandon From what I am seeing the action is actually executing even after a redirect takes place. I'm thinking this might be because all the redirect is doing is setting response codes on the Response object. It isn't actually stopping MVC from executing the action... I need to research this further, but that's the current thinking...
Paul Fryer
Could be. Check out the source for the AuthorizationAttribute: http://aspnet.codeplex.com/SourceControl/changeset/view/55373#266447looks like you might try replacing the redirect with `filterContext.Result = new HttpUnauthorizedResult();`
Brandon Satrom
@Brandon I actually tried setting filterContext.Result after adding my comment. And sure enough it is now working as expected. So I guess MVC will actually continue to execute the Action unless you set it in the Authorize attribute. See edits in original post.
Paul Fryer
Awesome. I was just posting something similar in my original answer. Glad that worked for you!
Brandon Satrom