Search code examples
c#asp.net-mvcauthenticationforms-authentication

Can't redirect to original page after successful login


I've changed the web.config file adding the following lines.

<system.web>
  <authorization>
    <deny users="?"/>
  </authorization>
  <authentication mode="Forms">
    <forms loginUrl="~/Account/LogIn"></forms>
  </authentication>
</system.web>

Now, whatever page's accessed, I'm being redirected to the login page. That's great and as I enter the credentials, I'd like the user to be directed back to where they started.

public ActionResult LogIn(string token)
{
  using (Model model = new Model())
    if (model.Users.Any(_ => _.Token == token))
      return Redirect(Request.UrlReferrer.ToString());
  return View();
}

The problem I discover is that the UrlReferrer is the login page itself so I'm only redirecting to where I'm already at on the log in page, instead of where I originally started...

What am I doing wrong?


Solution

  • What am I doing wrong?

    You are using the old ASP.NET security (which is based on physical files and folders) for MVC (which is based on controllers and actions). The proper way to secure controllers and actions is to use AuthorizeAttribute. ASP.NET security won't work for MVC controllers because they are not file-system based (but do note it does still come in handy for physical files - you can block direct access to them and then use a controller to provide conditional access).

    When you use AuthorizeAttribute, the login URL will automatically be built with a ReturnUrl query string parameter which is used to redirect the user back to the location they started at.

    For example, in the default MVC templates, this is the Login method which uses the returnUrl. It also uses RedirectToLocal to ensure someone doesn't exploit the query string parameter to hijack the user to another website.

    MVC 4 (Simple Membership):

        [HttpPost]
        [AllowAnonymous]
        [ValidateAntiForgeryToken]
        public ActionResult Login(LoginModel model, string returnUrl)
        {
            if (ModelState.IsValid && WebSecurity.Login(model.UserName, model.Password, persistCookie: model.RememberMe))
            {
                return RedirectToLocal(returnUrl);
            }
    
            // If we got this far, something failed, redisplay form
            ModelState.AddModelError("", "The user name or password provided is incorrect.");
            return View(model);
        }
    

    MVC 5 (Identity):

        [HttpPost]
        [AllowAnonymous]
        [ValidateAntiForgeryToken]
        public async Task<ActionResult> Login(LoginViewModel model, string returnUrl)
        {
            if (!ModelState.IsValid)
            {
                return View(model);
            }
    
            // This doesn't count login failures towards account lockout
            // To enable password failures to trigger account lockout, change to shouldLockout: true
            var result = await SignInManager.PasswordSignInAsync(model.Email, model.Password, model.RememberMe, shouldLockout: false);
            switch (result)
            {
                case SignInStatus.Success:
                    return RedirectToLocal(returnUrl);
                case SignInStatus.LockedOut:
                    return View("Lockout");
                case SignInStatus.RequiresVerification:
                    return RedirectToAction("SendCode", new { ReturnUrl = returnUrl, RememberMe = model.RememberMe });
                case SignInStatus.Failure:
                default:
                    ModelState.AddModelError("", "Invalid login attempt.");
                    return View(model);
            }
        }