MVC 4.0 FormsAuthentication and AuthorizeAttribute in custom authorization

12,439

You're almost there. Right now what's happening is that you set the principal to a custom principal, and the SimpleMembership provider comes in after you and blows away your principal by setting it to a System.Web.Security.RolePrincipal. Move your current Application_AuthenticateRequest code into a new Application_PostAuthenticateRequest handler and your custom principal will remain in place.

Share:
12,439
Emil J
Author by

Emil J

Updated on July 16, 2022

Comments

  • Emil J
    Emil J almost 2 years

    I am using MVC4 and I'm trying to modify the allocation procedure for authenticating a user and assign roles to users. Everything works fine for the attribute [Authorize (Users = "adminadmin")], but the [Authorize (Roles = "Admin")] every time there is a login page and lack of access.

    Global.asax.cs:

    protected void Application_AuthenticateRequest(object sender, EventArgs e)
            {
                // look if any security information exists for this request
                if (HttpContext.Current.User != null)
                {
                    // see if this user is authenticated, any authenticated cookie (ticket) exists for this user
                    if (HttpContext.Current.User.Identity.IsAuthenticated)
                    {
                        // see if the authentication is done using FormsAuthentication
                        if (HttpContext.Current.User.Identity is FormsIdentity)
                        {
                            // Get the roles stored for this request from the ticket
                            // get the identity of the user
                            FormsIdentity identity = (FormsIdentity)HttpContext.Current.User.Identity;
                            //Get the form authentication ticket of the user
                            FormsAuthenticationTicket ticket = identity.Ticket;
                            //Get the roles stored as UserData into ticket
                            List<string> roles = new List<string>();
                            if (identity.Name == "adminadmin")
                                roles.Add("Admin");
                            //Create general prrincipal and assign it to current request
    
                            HttpContext.Current.User = new System.Security.Principal.GenericPrincipal(identity, roles.ToArray());
                        }
                    }
                }
            }
    

    AccountController:

    [InitializeSimpleMembership]
    public class AccountController : Controller
    {
    public ActionResult Login()
    {
        return View();
    }
    
    [HttpPost]
    public ActionResult Login(LoginModel model, string returnUrl)
    {
        // Lets first check if the Model is valid or not
        if (ModelState.IsValid)
        {
                string username = model.UserName;
                string password = model.Password;
    
                bool userValid = username == password ? true : false;
    
                // User is valid
                if (userValid)
                {
    
                    FormsAuthentication.SetAuthCookie(username, false);
                    if (Url.IsLocalUrl(returnUrl) && returnUrl.Length > 1 && returnUrl.StartsWith("/")
                        && !returnUrl.StartsWith("//") && !returnUrl.StartsWith("/\\"))
                    {
                        return Redirect(returnUrl);
                    }
                    else
                    {
                        return RedirectToAction("Index", "Home");
                    }
                }
                else
                {
                    ModelState.AddModelError("", "The user name or password provided is incorrect.");
                }
        }
    
        // If we got this far, something failed, redisplay form
        return View(model);
    }
    
    public ActionResult LogOff()
    {
        FormsAuthentication.SignOut();
    
        return RedirectToAction("Index", "Home");
    }
    

    }

    HomeController.cs:

     public class HomeController : Controller
        {
            [AllowAnonymous]
            public ActionResult Index()
            {
                ViewBag.Message = "Modify this template to jump-start your ASP.NET MVC application.";
    
                return View();
            }
    
            [Authorize]
            public ActionResult About()
            {
                ViewBag.Message = "Your app description page.";
    
                return View();
            }
    
            [Authorize(Roles = "Admin")]
            public ActionResult Contact()
            {
                ViewBag.Message = "Your contact page.";
    
                return View();
            }
        }
    

    Web.config:

    (...)
        <authentication mode="Forms">
          <forms loginUrl="~/Account/Login" timeout="2880"/>
        </authentication>
    (...)
    
  • hubert17
    hubert17 over 3 years
    Moving the code to Application_PostAuthenticateRequest is the VERY correct answer! Thank you very much!