9

I'm in a bit of a bind with implementing Roles in ASP.NET MVC 5. I am attempting to log in as a user that does not have a role required to access the area of the application I'm trying to reach. What I would expect in this scenario is, I'm redirected to the login page again, and will be until I enter a set of credentials that do have access or I navigate to another area of the application.

What is actually happening is that the application appears to go into a login redirect loop, debugging through reveals that the Login action is being called multiple times.

Here is the login action:

[AllowAnonymous]
public ActionResult Login(string returnUrl)
{
    ViewBag.ReturnUrl = returnUrl;
    return View();
}

This results in an error generated by IIS:

HTTP Error 404.15 - Not Found
The request filtering module is configured to deny a request where the query string is too long.

The query string looks like this:

http://localhost/MyApplication/Account/Login?ReturnUrl=%2FMyApplication%2FAccount%2FLogin%3FReturnUrl%3D%252FMyApplication%252FAccount%252FLogin%253FReturnUrl%253D%25252FMyApplication%25252FAccount%25252FLogin%25253FReturnUrl%25253D%2525252FMyApplication%2525252FAccount%2525252FLogin%2525253FReturnUrl%2525253D%252525252FMyApplication%252525252FAccount%252525252FLogin%252525253FReturnUrl%252525253D%25252525252FMyApplication%25252525252FAccount%25252525252FLogin%25252525253FReturnUrl%25252525253D%2525252525252FMyApplication%2525252525252FAccount%2525252525252FLogin%2525252525253FReturnUrl%2525252525253D%252525252525252FMyApplication%252525252525252FAccount%252525252525252FLogin%252525252525253FReturnUrl%252525252525253D%25252525252525252FMyApplication%25252525252525252FAccount%25252525252525252FLogin%25252525252525253FReturnUrl%25252525252525253D%2525252525252525252FMyApplication%2525252525252525252FAccount%2525252525252525252FLogin%2525252525252525253FReturnUrl%2525252525252525253D%252525252525252525252FMyApplication%252525252525252525252FAccount%252525252525252525252FLogin%252525252525252525253FReturnUrl%252525252525252525253D%25252525252525252525252FMyApplication%25252525252525252525252FAccount%25252525252525252525252FLogin%25252525252525252525253FReturnUrl%25252525252525252525253D%2525252525252525252525252FMyApplication%2525252525252525252525252FAccount%2525252525252525252525252FLogin%2525252525252525252525253FReturnUrl%2525252525252525252525253D%252525252525252525252525252FMyApplication%252525252525252525252525252FAccount%252525252525252525252525252FLogin%252525252525252525252525253FReturnUrl%252525252525252525252525253D%25252525252525252525252525252FMyApplication%25252525252525252525252525252FAccount%25252525252525252525252525252FLogin%25252525252525252525252525253FReturnUrl%25252525252525252525252525253D%2525252525252525252525252525252FMyApplication%2525252525252525252525252525252FAccount%2525252525252525252525252525252FLogin%2525252525252525252525252525253FReturnUrl%2525252525252525252525252525253D%252525252525252525252525252525252FMyApplication%252525252525252525252525252525252F

The only change I've made going from a working solution (albeit without role based authorization) to my current broken situation is adding the following above the controller that I'm redirected to on a successful login:

[Authorize(Roles = "Staff")]

As I said previously, the user I'm logging in as is not in this role, but I would expect a sane, single redirect to Login, without the looping.

Edit: requested bu @dima, the details of authorization applied through filters... I have the following:

public class FilterConfig
{
    public static void RegisterGlobalFilters(GlobalFilterCollection filters)
    {
        filters.Add(new HandleErrorAttribute());
        filters.Add(new AuthorizeAttribute());
    }
}

However, I have tested the application with and without this line in place and the redirect loop continues unabated.

A. Murray
  • 2,761
  • 5
  • 27
  • 40
  • Did you happen to create a new global filter for role authentication or made any changes to global filters or other code or config that is used by authentication/authorization? If so, share it! – dima Apr 16 '14 at 16:37
  • Good point @dima, I'll add that. – A. Murray Apr 17 '14 at 12:07
  • kudos for posting a 'StackOverflow' exception albeit in the form of a HTTP 'the query string is too long' exception. – Rudi Apr 17 '14 at 12:41
  • take a look at [this](http://stackoverflow.com/questions/1472496/log-in-loop-asp-net-mvc-view-with-authorize-attribute) and [this](http://stackoverflow.com/questions/238437/why-does-authorizeattribute-redirect-to-the-login-page-for-authentication-and-au).. hopefully it's going to help you – dima Apr 17 '14 at 16:33

3 Answers3

12

While this question is old, I had the same problem and found a solution.

Originally, I had added the same AuthorizationAttribute filter, and found myself in the same loop. I then took it away and began adding the authorize attribute to individual controllers, and found that the infinite loop only happened when adding the authorize attribute to my home controller. It turns out my HomeController was getting called after my AccountController.

The Problem


In my _Layout.cshtml, I was calling the following:

@Html.Action("LeftNav", "Home")

The layout page would correctly render the body, but when it got to this, it was hitting a controller method that had an authorization attribute. This caused the redirect to the Account/Login.

Adding the AllowAnonymous attribute to the LeftNav action resolved the issue.

The Solution


Make sure your Login view and layouts do not call any actions that have an authorize attribute.

Since discovering this, I've created a custom layout for my unauthorized requests to avoid any more potential issues like this.

  • Thanks for posting this @silencedmessage, this was the exact same situation that I was in. I forgot to go back and update this question, so thanks for the very good explanation. – A. Murray Sep 25 '14 at 09:54
  • @A.Murray I'm working with same example given in question but answer isn't working for me.I've removed all connections to `HomeController` from `LoginController` as well as all connections from `LoginControllers` to `_Layout` view or any other connection leading to any action in `HomeController`.Obviously initial URL request is default (/Home/Index) but since AuthorizeAttribute filter is applied globally,it redirects the request to LoginController's login page where credentials are correctly supplied but instead of returning back to originally requested URL,it is falling into URL infinite loop – Jogi Jan 23 '16 at 00:24
  • I am speechless about this fix absolutely amazing solution, Thumbs up for silencedmessage! – Coding Freak Apr 20 '16 at 18:48
0

I was working on the same example given in the question but the answer (marked) given by @silencedmessage couldn't solve my situation despite i disconnected all the links between the Home controller and Account controller and between Account controller and _layout view. If someone is facing this same situation as me, I recommend adding following step to the solution:

Since the AuthorizeAttribute in this very example is applied globally, all its action methods are secured by default and don't allow 'annonymous' access. In this very example, [AllowAnnonymous] attribute is only applied to [HttpGet] login Action Method. It is not applied to [HttpPost] login ActionMethod and since AuthorizeAttribute is applied globally, it is securing [HttpPost] login ActionMethod as well, hence [HttpPost] login ActionMethod is not executing, and you are being redirected to [HttpGet] login ActionMethod infinitely.

By simply adding [AllowAnnonymous] to [HttpPost] login ActionMethod solved my situation.

Hope it helps.

Jogi
  • 1
  • 2
  • 14
  • 29
0

If anyone's having issues MVC going back to login with out any error, whe running in Visual Studio/IIS Express make sure the project is set to use SSL and use the https local host address when logging in.

ElBenito
  • 11
  • 1
  • 2