Question

Some background: Our client wanted a number of actions to return to the previous action when done. For example, if he was on a list view of objects and he clicked on "create new object" button, he wanted to return to the list view after he fills and saves the form or after he cancels the action. We implemented it by mimicking the ReturnUrl behavior that is used with unauthorized access attempts (adding current address as an url encoded query parameter).

The problem: If I'm not authorized (or in other words not logged in) and try to access an action that requires it I get redirected to login page (as I should) and current url gets put into ReturnUrl param. However, when the current address already contains ReturnUrl query param, I'm not being redirected anywhere and instead I get a blank page. Is there any reason why this happens?

The expected result would be being redirected to the login screen with the (url encoded version of) current url put into the ReturnUrl param (regardless of whether the current url contained its own ReturnUrl param or not)

Is there some way to make it work as expected? Sure in theory I could rename the "ReturnUrl" param (in my own actions) to something else, but we used such parameter in so many places already that renaming them is not going to be an easy task. Besides, I don't really understand why this doesn't work in the first place.

P.S. The problem only occurs if I name the parameter ReturnUrl, if it's returnUrl everything works as it should.


Edit: This question was previously called: Unauthorized access to restricted actions returns nothing if the url contains parameter called ReturnUrl. I changed the title to make it easier to understand.


Edit: This question might be a duplicate of Unauthorized request does not redirect to login page with returnUrl query string parameter. I'll have to investigate further if the solution provided there solves my issue or not. Update: The wording is similar, but the problem is different after all, so it's not a duplicate.

Was it helpful?

Solution

Thise proved a major pain to fix, but I managed to do that. In the quest to find why the redirect to login fails for some urls I had to answer myself an important question. What is actually responsible for doing the redirect and how can I override that?

This article put me on track (the thing responsible for the redirect was the [Authorize] filter) and I started searching for a solution. After a little bit of searching I found this simple custom Authorization filter. Of course it didn't do what I want out of the box (and what I want is basically for authorize to work like normally but not to break on urls that contain ReturnUrl param), so I altered the code and got this:

public class Authorize2 : AuthorizeAttribute
{
    protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
    {
        // 1. Get the default login url that was declared in web.config
        string returnUrl = FormsAuthentication.LoginUrl;
        // 2. Append current url as a return url to the login url
        returnUrl += "?ReturnUrl=" + HttpUtility.UrlEncode(HttpContext.Current.Request.Url.PathAndQuery);
        // 3. ...
        // 4. Profit
        filterContext.Result = new RedirectResult(returnUrl);
    }
}

After writing this piece of code, I spent another hour trying to figure out why it doesn't work (breakpoints inside of HandleUnauthorizedRequest were never hit). Then I found this site and it suddenly made sense. A colleague of mine added a global Authorize filter to all actions for whatever reason and my own custom filter was never asked to authorize anything (\App_Start\FilterConfig.cs). After removing that line (I'll have to put my custom filter in its place eventually), the code above worked like a charm.

In a way the question is still open, I mean it's still a mystery why Authorize fails for those urls. The answer to that question undoubtedly lies in System.Web.Mvc.AuthorizeAttribute source code, but for now I'm satisfied with just having it work correctly.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top