MVC 5 Prevent Users From Going Back After Logging In or Out Using Identity Framework

Steven Petersen 1 Reputation point
2022-04-03T19:29:27.11+00:00

I am building an app using MVC 5 and I ran into a common issue that has been asked over and over but I can't seem to find the right answer using .NET Identity. Once the user logs in, they should not be able to go back to the login page and the same is true when they log out they should not be able to go back to a restricted page.

The problem that I'm having is that if a user does not enter the correct password and the server catches the error then I successfully login I am able to go back to the login page. If I login on the first try it works like it should. How can I correct this problem?

The other problem that I'm having is when the user logs out, Is there any way without using javascript to not allow the user to access the restricted pages by using the back button?

I have included

filters.Add(new System.Web.Mvc.AuthorizeAttribute());

in my filterconfig.cs file.

My controller looks like this:

[AllowAnonymous]
    [OutputCache(NoStore = true, Location = OutputCacheLocation.None)]
    public ActionResult Login(string returnUrl)
    {
        if (User.Identity.IsAuthenticated)
        {
            return RedirectToAction("Dashboard", "App");
        }
        ViewBag.ReturnUrl = returnUrl;
        return View();
    }

    //
    // POST: /Account/Login
    [HttpPost]
    [AllowAnonymous]
    [ValidateAntiForgeryToken]
    public async Task<ActionResult> Login(LoginViewModel model, string returnUrl)
    {
        if (!ModelState.IsValid)
        {
            return View(model);
        }

        // Require the user to have a confirmed email before they can log on.
        var user = await UserManager.FindByNameAsync(model.Email);
        if (user != null)
        {
            if (!await UserManager.IsEmailConfirmedAsync(user.Id))
            {
                string callbackUrl = await SendEmailConfirmationTokenAsync(user.Id, "Confirm your account-Resend");
                ViewBag.errorMessage = "You must have a confirmed email to log on.";
                return View("Error");
            }
        }

        // 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 RedirectToAction("Dashboard","App");
            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);
        }
    }

My Logout Controller is:

// POST: /Account/LogOff
    [HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult LogOff()
    {
        AuthenticationManager.SignOut(DefaultAuthenticationTypes.ApplicationCookie);
        return RedirectToAction("Index", "Home");
    }

I didn't add anything special to my view. How do I prevent the logged in user from going back to the login page which they can do if they have an error. and how can I prevent the user from going back after logout and seeing a restricted page. What I really want to know is if there is any way to do this with Identity?

I know the issue is caching in the browser that allows the user to go back. I've cleared the cache when I logout, I used the [OutputCache(NoStore = true, Location = OutputCacheLocation.None)]I do not want to disable cashing for the whole app (performance issues) and I do not want to use javascript (since it can be disabled by the user). Is there any other way to do it?

I know this question has been asked a million times but I haven't really found a definitive answer that works on all browsers.

ASP.NET
ASP.NET
A set of technologies in the .NET Framework for building web applications and XML web services.
3,417 questions
C#
C#
An object-oriented and type-safe programming language that has its roots in the C family of languages and includes support for component-oriented programming.
10,650 questions
{count} votes

2 answers

Sort by: Most helpful
  1. AgaveJoe 27,696 Reputation points
    2022-04-04T14:04:07.213+00:00

    The code snippet (attribute) you shared disables cache on a specific action or controller not the entire application.

    Is there any other way to do it?

    Caching is also a browser feature. If you don't want the browser to cache resources then you have to configure your application to tell/ask the browser to stop caching; HTTP response. This can be configured at the application level or action. If the browser already cached the resource then you need to press ctrl-F5 to reload the page. This forces the browser to get the page from the server and any caching configuration changes in the HTTP header for that page.

    0 comments No comments

  2. SurferOnWww 2,491 Reputation points
    2022-04-05T00:18:36.127+00:00

    as I stated in my original post filters.Add(new System.Web.Mvc.AuthorizeAttribute()); Was added to my filtersconfig file so after they log out they shouldn’t be allowed to see the page before because they are not authorized

    Although I do not know how the filter you installed works I believe "after they log out they shouldn’t be allowed to see the page before" is not possible or at least not practical. The reasons are:

    The logged-out user does not have the authentication ticket/cookie which is required for the ASP.NET Core Identity to know who he is.

    A new user who has never logged-in before does not have the authentication ticket/cookie either.

    There is no way for the ASP.NET Core Identity to identify who the user accessing without the authentication ticket/cookie is. Nobody knows whether such user is a logged-out user or a new user.

    How does your filter be able to deny the logged-out user to visit and login again? ASP.NET Core Identity does not have such provisions to detect second login try by the logged-out user.

    0 comments No comments