Search code examples
c#asp.net-mvc-5asp.net-identity-2

ASP.NET Identity user null after login


Edit 1

Having updated the code to better handle this problem, I'm now running into the following problem:

The provided anti-forgery token was meant for a different claims-based user than the current user.

Here's the updated code:

var result = await SignInManager.PasswordSignInAsync(model.Email, model.Password, model.RememberMe, shouldLockout: false);
if (result == SignInStatus.Success)
{
    var store = new UserStore<ApplicationUser>(new ApplicationDbContext());
    var manager = new UserManager<ApplicationUser>(store);
    var user = manager.FindById(User.Identity.GetUserId());
    GenerateUserCookie(model, user, returnUrl);
}
switch (result)
{
    case SignInStatus.LockedOut:
        return View("Lockout");
    case SignInStatus.RequiresVerification:
        return RedirectToAction("SendCode", new { ReturnUrl = returnUrl, RememberMe = model.RememberMe });
    case SignInStatus.Failure:
        ModelState.AddModelError("", "Invalid login attempt.");
        return View(model);
    default:
        return View(model);
}

private ActionResult GenerateUserCookie(LoginViewModel model, ApplicationUser user, string returnUrl)
{
    if (user == null)
    {
        ModelState.AddModelError("", "Someething went wrong; please try logging in again.");
        return View(model);
    }

    var cookie = new HttpCookie("stman");
    if (user.AgentId >= 1) cookie.Values.Add("aid", user.AgentId.ToString());

    cookie.Values.Add("wumpus", user.Id.ToString());
    Response.Cookies.Add(cookie);
    return RedirectToLocal(returnUrl);
}

Original Question

Like the title says, after I log in, the user value returned by the following code is still null.

To actually get a user, I have to open the login screen again (not refresh) and log in again...

[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:
            var store = new UserStore<ApplicationUser>(new ApplicationDbContext());
            var manager = new UserManager<ApplicationUser>(store);
            var user = manager.FindById(User.Identity.GetUserId());
            GenerateUserCookie(user);
            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);
    }
}

private void GenerateUserCookie(ApplicationUser user)
{
    var cookie = new HttpCookie("stman");

    // Throws exception most times since the user is null.
    if (user.AgentId >= 1)
    {
        cookie.Values.Add("aid", user.AgentId.ToString());
    }
    cookie.Values.Add("wumpus", user.Id.ToString());
    Response.Cookies.Add(cookie);
}

Solution

  • The issue is that User.Identity is unavailable until after you redirect. An easy way around this is to use the username rather than id to get the correct ApplicationUser.

    var manager = new UserManager<ApplicationUser>(store);
    var user = manager.FindByName(model.UserName);
    GenerateUserCookie(user);