I have the following code I've typed into the Account Controller in my MVC project and I am in both the administrator and manager roles. When I log in I get redirected back to my home index instead of being redirected to my AdminApp index. Any ideas where I'm going wrong in my code?
[AcceptVerbs(HttpVerbs.Post)]
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1054:UriParametersShouldNotBeStrings",
Justification = "Needs to take same parameter type as Controller.Redirect()")]
public ActionResult LogOn(string userName, string password, bool rememberMe, string returnUrl)
{
if (!ValidateLogOn(userName, password))
{
return View();
}
FormsAuth.SignIn(userName, rememberMe);
if (!String.IsNullOrEmpty(returnUrl))
{
return Redirect(returnUrl);
}
else
{
if (User.IsInRole("Administrator") || (User.IsInRole("Manager")))
{
return RedirectToAction("Index", "AdminApp");
}
else
{
return RedirectToAction("Index", "Home");
}
}
}
The reason your code is not working as expected is because the User
has technically not been signed in and authenticated yet. Say what? But you did call SignIn!
FormsAuth.SignIn(userName, rememberMe);
- which in this case is just a wrapper for FormsAuthentication.SetAuthCookie(userName, createPersistentCookie);
- only sets the asp.net authorization cookie on the users browser as part of the response. It is only for requests after this point that the user's browser will have the cookie, causing the asp.net membership to properly set up the 'User' object. All of your code in the LogOn method is still assuming an anonymous user, so your IsInRole check fails and you are redirected home. Put your if statement on another page and after you've signed in, you'll see that now User.IsInRole
works as expected. (And indeed, this is what you'd use User.IsInRole for, just not during the logon process)
So how to check during the actual logon process? Roles.IsUserInRole
or Roles.GetRolesForUser
are a couple of ways, eg.:
if (Roles.IsUserInRole(userName, "Administrator") || Roles.IsUserInRole(userName, "Administrator"))
{
return RedirectToAction("Index", "AdminApp");
}
You must explicitly specify the user name of the user logging in, which will actually execute a query against the membership datastore. On that note, I believe the above code would as a result cause two queries to be executed, which you may find less than ideal. This is where Roles.GetRolesForUser might be a better option:
string[] roles = Roles.GetRolesForUser(userName);
if (roles.Contains("Administrator") || roles.Contains("Manager"))
{
return RedirectToAction("Index", "AdminApp");
}
Hope that helps!
I'm using VS 2013 and it's new Identity model, I ended up going with this:
foreach (IdentityUserRole identityUserRole in user.Roles)
{
if (identityUserRole.RoleId == "AdminRoleId")
{
return RedirectToAction("Index", "Admin");
}
else if (identityUserRole.RoleId == "MemberRoleId")
{
return RedirectToAction("Index", "Members");
}
}
You need to un-nest the if statement. Revise as follows:
Change this:
FormsAuth.SignIn(userName, rememberMe);
if (!String.IsNullOrEmpty(returnUrl))
{
return Redirect(returnUrl);
}
else
{
if (User.IsInRole("Administrator") || (User.IsInRole("Manager")))
{
return RedirectToAction("Index", "AdminApp");
}
else
{
return RedirectToAction("Index", "Home");
}
}
to this:
if (User.IsInRole("Administrator") || (User.IsInRole("Manager")))
{
return RedirectToAction("Index", "AdminApp");
}
else
{
return RedirectToAction("Index", "Home");
}
The problem is the the line if(!String.IsNullOrEmpty(returnUrl)))
is evaluating to True because the returnUrl parameter has the url of the page you came from by default.