Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Custom form authentication / Authorization scheme in ASP.net MVC

I am trying to create a custom authentication scheme in ASP.NET MVC using form authentication. The idea that I might have different areas on the site that will be managed - approver are and general user area, and these will use different login pages, and so forth. So this is what I want to happen.

  1. User access restricted page (right now I have it protected with a customer AuthorizeAttribute)
  2. User is redirected to a specific login page (not the one from Web.config).
  3. User credentials are verified (via custom databse scheme) and user logs in.

Would really appreciate any help with this!!!

This is what I what I have so far, and it doesn't work:

 public class AdministratorAccountController : Controller
{
    public ActionResult Login()
    {
        return View("Login");
    }

    [HttpPost]
    public ActionResult Login(AdministratorAccountModels.LoginModel model, string returnUrl)
    {
        if (ModelState.IsValid)
            if (model.UserName == "admin" && model.Password == "pass") // This will be pulled from DB etc
            {
                var ticket = new FormsAuthenticationTicket(1,               // version 
                                                           model.UserName,  // user name
                                                           DateTime.Now,    // create time
                                                           DateTime.Now.AddSeconds(30), // expire time
                                                           false,           // persistent
                                                           "");             // user data

                var strEncryptedTicket = FormsAuthentication.Encrypt(ticket);
                var cookie = new HttpCookie(FormsAuthentication.FormsCookieName, strEncryptedTicket);
                Response.Cookies.Add(cookie);

                if (!String.IsNullOrEmpty(returnUrl))
                {
                    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);
    }

    [AdministratorAuthorize]
    public ActionResult MainMenu()
    {
        return View();
    }

    public class AdministratorAuthorizeAttribute : AuthorizeAttribute
    {
        protected override bool AuthorizeCore(HttpContextBase httpContext)
        {
            var authenCookie = httpContext.Request.Cookies.Get(FormsAuthentication.FormsCookieName);
            if (authenCookie == null) return false;

            var ticket = FormsAuthentication.Decrypt(authenCookie.Value);
            var id = new FormsIdentity(ticket);
            var astrRoles = ticket.UserData.Split(new[] { ',' });
            var principal = new GenericPrincipal(id, astrRoles);
            httpContext.User = principal;
            return true;
        }

        protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
        {
            var model = new AdministratorAccountModels.LoginModel();
            var viewData = new ViewDataDictionary(model);

            filterContext.Result = new ViewResult { ViewName = "Login", ViewData = viewData };

        }
    }
}
like image 734
Greg R Avatar asked Feb 24 '10 20:02

Greg R


People also ask

What is authentication and authorization in ASP.NET MVC?

A user is authenticated by its identity and assigned roles to a user determine about authorization or permission to access resources. ASP.NET provides IPrincipal and IIdentity interfaces to represents the identity and role for a user.


1 Answers

I used a combination of code suggested by minus4 and my own code above to create this simplified scenario that might help someone else. I added some comments about things that confused me at first.

 public class AdministratorAccountController : Controller
{
    public ActionResult Login()
    {
        return View("Login");
    }

    [HttpPost]
    public ActionResult Login(AdministratorAccountModels.LoginModel model, string returnUrl)
    {
        if (ModelState.IsValid)
            // Here you would call a service to process your authentication
            if (model.UserName == "admin" && model.Password == "pass")
            {
                // * !!! *
                // Creating a FromsAuthenticationTicket is what 
                // will set RequestContext.HttpContext.Request.IsAuthenticated to True
                // in the AdminAuthorize attribute code below
                // * !!! *
                var ticket = new FormsAuthenticationTicket(1, // version 
                                                           model.UserName, // user name
                                                           DateTime.Now, // create time
                                                           DateTime.Now.AddSeconds(30), // expire time
                                                           false, // persistent
                                                           ""); // user data, such as roles

                var strEncryptedTicket = FormsAuthentication.Encrypt(ticket);
                var cookie = new HttpCookie(FormsAuthentication.FormsCookieName, strEncryptedTicket);
                Response.Cookies.Add(cookie);

                // Redirect back to the page you were trying to access
                if (!String.IsNullOrEmpty(returnUrl))
                {
                    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);
    }

    [AdminAuthorize]
    public ActionResult MainMenu()
    {
        return View();
    }

    public class AdminAuthorize : ActionFilterAttribute
    {
        public override void OnActionExecuting(ActionExecutingContext filterContext)
        {
            if (!filterContext.RequestContext.HttpContext.Request.IsAuthenticated)
            {
                // Redirect to the needed login page
                // This can be pulled from config file or anything else
                filterContext.HttpContext.Response.Redirect("/AdministratorAccount/Login?ReturnUrl=" 
                                        + HttpUtility.UrlEncode(filterContext.HttpContext.Request.RawUrl));               
            }

            base.OnActionExecuting(filterContext);
        }
    }
}
like image 177
Greg R Avatar answered Oct 22 '22 19:10

Greg R