Search code examples
c#asp.net-mvcuser-roles

setting user access to every app in asp.net mvc


here is my code and i dont know why it always executed the else statement even if i log in the user that has a role of SuperAdmin

 [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);

        if (User.IsInRole("SuperAdmin"))
        {
            switch (result)
            {
                case SignInStatus.Success:
                    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);
            }
        }

        else
        {
            ModelState.AddModelError("", "you are not allowed to access this page");
            //AuthenticationManager.SignOut(DefaultAuthenticationTypes.ApplicationCookie);
            return View(model);
        }

    }

Give me some suggestions what should i do to my code to improve it.. My issue is why my code always executing the else statement even if I use the account of SuperAdmin


Solution

  • Sounds like if statement for checking current user role should be moved. Ensure if the current user successfully logged in before proceeding for user role checking, because it is possible that user still not completed all authentication process after hitting PasswordSignInAsync method.

    If you're using newer version of Identity, use UserManager.IsInRole method instead, because User.IsInRole uses previous version of role manager:

    var user = await UserManager.FindAsync(model.Email, model.Password);
    if (UserManager.IsInRole(user.Id, "SuperAdmin"))
    {
        // do something
    }
    

    Here is an example setup for user role checking:

    [HttpPost]
    [AllowAnonymous]
    [ValidateAntiForgeryToken]
    public async Task<ActionResult> Login(LoginViewModel model, string returnUrl)
    {
        if (!ModelState.IsValid)
        {
            return View(model);
        }
    
        var result = await SignInManager.PasswordSignInAsync(model.Email, model.Password, model.RememberMe, shouldLockout: false);
    
        switch (result)
        {
            case SignInStatus.Success:
                 var user = await UserManager.FindAsync(model.Email, model.Password);
    
                 if (user == null)
                 {
                     // user not found or login failure, do something here
                 }
                 else 
                 {
                     // proceed to role checking
                     var roles = await UserManager.GetRolesAsync(user.Id);
    
                     // use roles.Contains("SuperAdmin") if IsInRole still won't work 
                     if (UserManager.IsInRole(user.Id, "SuperAdmin"))
                     {
                         return RedirectToLocal(returnUrl);
                     }
                     else
                     {
                         ModelState.AddModelError("", "you are not allowed to access this page");
                         return View(model);
                     }
                 }      
    
                 break;
            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);
    }
    

    Note: Make sure roleManager setting in web.config has properly set and/or Roles table has joined with Users table in database to take effect.