views:

104

answers:

2

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");
            }

        }
    }
A: 

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.

Jeff French
hmm. I tried and didn't work for me. I can use the User.InInRole successfully on an aspx page to show/hide links, but it's not working when I have it in a controller. Is there another way to perform this in the controller?
Ben
Shouldn't make much difference, but you can try Roles.IsUserInRole(). However, I think this is the same method that ends up getting called by the User.IsInRole() method.
Jeff French
+4  A: 

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!

Kurt Schindler
worked like a charm! I appreciate the help!
Ben