I was changing the default LogOn function in an MVC3 project to redirect a user to a certain page based on their role
by using User.IsInRole()
. When I was testing this out, the first couple users redirected as expected, but after that I had a couple that didn't redirect to where they are supposed to (they passed through all the statements and hit the default home index.) It seems completely random, sometimes my admin
will be taken to the admin page, other times not.
My LogOn function:
[HttpPost]
public ActionResult LogOn(LogOnModel model, string returnUrl)
{
if(ModelState.IsValid)
{
if(Membership.ValidateUser(model.UserName, model.Password))
{
FormsAuthentication.SetAuthCookie(model.UserName, model.RememberMe);
if(Url.IsLocalUrl(returnUrl) && returnUrl.Length > 1 &&
returnUrl.StartsWith("/") && !returnUrl.StartsWith("//") &&
!returnUrl.StartsWith("/\\"))
{
return Redirect(returnUrl);
}
else
{
if(User.IsInRole("Admin") || User.IsInRole("SuperAdmin"))
{
return RedirectToAction("Index", "Admin");
}
else if(User.IsInRole("Employee"))
{
return RedirectToAction("Index", "Employee");
}
else if(User.IsInRole("Accounting"))
{
return RedirectToAction("Index", "Accounting");
}
// If the user is in none of those roles, send them to the home index
return RedirectToAction("Index", "Home");
}
}
else
{
MembershipUser user = Membership.GetUser(model.UserName);
if(user == null)
ModelState.AddModelError("", "The user name or password provided is incorrect.");
else
ModelState.AddModelError("", "You haven't been approved yet, or you are locked out.");
}
}
// If we got this far, something failed, redisplay form
return View(model);
}
Looking at the IntelliTrace, it seems like sometimes it doesn't bother to query the database, for example, when it works I see Execute Reader "dbo.aspnet_UsersInRoles_GetRolesForUser"
and when it doesn't I don't.
Does anyone know why User.IsInRole()
would return false even if the user is in the role? Is there some form of cashing happening, why isn't it queering the database every time?
I know for sure the users are in the roles I am testing, and I know it is not trying to redirect to the return url, I also know that the role isn't being stored in any cookies. Any ideas would be appreciated, I'm sure I could go about this another way, however now I'm more interested in why this simple approach isn't working.
Update
I found that if i replace the If(User.IsInRole(...
statements with a redirect to another action called sorting, and I add the if statements there, it works 100% of the time.
public ActionResult Sorting()
{
if(User.IsInRole("Admin") || User.IsInRole("SuperAdmin"))
{
return RedirectToAction("Index", "Admin");
}
else if(User.IsInRole("Employee"))
{
return RedirectToAction("Index", "Employee");
}
else if(User.IsInRole("Accounting"))
{
return RedirectToAction("Index", "Accounting");
}
// If the user is in none of those roles, send them to the home index
return RedirectToAction("Index", "Home");
}
So apparently User.Identity.Name
is not set (or will not return the user's name) until the LogOn
function exits. Is this correct? I figured that after the Membership.ValidateUser
was called the user was authenticated, apparently not.
So at what point after Membership.ValidateUser()
is called, will the User.IsInRole()
going to work correctly? Is is after the cookie is dropped, or what?
I suppose I could use if(Roles.IsUserInRole(model.UserName, "Admin"))
since I do have the user's name from the model submitted. Do you think this is a better idea or just use the Sorting
redirect like I did?