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.
Author by
Emil J
Updated on July 16, 2022Comments
-
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 over 3 yearsMoving the code to Application_PostAuthenticateRequest is the VERY correct answer! Thank you very much!