1
votes

My MVC web is acting weird. When I login for the first time, the User.IsInRole("Admin") is returning true and everything works as expected.

But after I login and logout, when i try to login again, the User.IsInRole("Admin") always returns false. But this problem fixed after I tried to login again.

This is the code:

[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public ActionResult Login(LoginModel model, string returnUrl)
{
    string redirectUrl = returnUrl;
    string userName = model.UserName;
    UserProfile user = dbAccount.UserProfiles.Where(m => m.Email.Equals(userName, StringComparison.CurrentCultureIgnoreCase)).SingleOrDefault();
    if (user != null)
    {
        userName = user.UserName;
    }

    if (ModelState.IsValid && WebSecurity.Login(userName, model.Password, persistCookie: model.RememberMe))
    {
        if (redirectUrl == null)
        {
            redirectUrl = User.IsInRole("Admin") ? "/Admin" : "/";
        }
        return RedirectToLocal(redirectUrl);
    }
    // If we got this far, something failed, redisplay form
    ModelState.AddModelError("", "The user name or password provided is incorrect.");         
    return View(model);
}

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult LogOff()
{
    WebSecurity.Logout();
    Roles.DeleteCookie();
    return RedirectToAction("Home", "Page");
}

Somehow after I logout, and login, the WebSecurity.Login() not giving me the correct user role.

1
"When I login for the first time, the User.IsInRole("Admin") is returning true" - I don't believe this: I suspect redirectUrl is non-null, and therefore that you aren't calling User.IsInRole. - Joe

1 Answers

1
votes

Your issue is that User.IsInRole() method gets the roles from authentication token that is serilaized in the authentication cookie. In your login action the cookie is not parsed yet so User.IsInRole() will always return false.

Why it works on the first login: My assumption that on the first login your user already logged in (the cookie is there) and this is why User.IsInRole("Admin") returns true. In order to test it before login (when you are on login page) clear all browser cookies and try to login - I assume that you'll get that User.IsInRole("Admin") is false.

But after I login and logout, when i try to login again, the User.IsInRole("Admin") always returns false: When you logout, you delete the authentication cookie, so in Login action the cookie is not there and this is the reason that User.IsInRole("Admin") is false.

Since this cookie will be parsed on the request that follows login you can do something like that:

UPDATED

public ActionResult Login(LoginModel model, string returnUrl)
{
    string redirectUrl = returnUrl;
    string userName = model.UserName;
    UserProfile user = dbAccount.UserProfiles.Where(m => m.Email.Equals(userName, StringComparison.CurrentCultureIgnoreCase)).SingleOrDefault();
    if (user != null)
    {
        userName = user.UserName;
    }

    if (ModelState.IsValid && WebSecurity.Login(userName, model.Password, persistCookie: model.RememberMe))
    {
        return  this.RedirectToAction("AdminRedirect","Account", new {redirectUrl = redirectUrl});           
    }
    // If we got this far, something failed, redisplay form
    ModelState.AddModelError("", "The user name or password provided is incorrect.");         
    return View(model);
}


public ActionResult AdminRedirect(string redirectUrl)
{
     if (redirectUrl == null)
     {
           redirectUrl = User.IsInRole("Admin") ? "/Admin" : "/";
     }
     return this.RedirectToLocal(redirectUrl);
 }

This way the user roles are checked after redirect so inside AdminRedirect action authentication cookie will already be parsed and user roles will be updated.