Custom user authorization based with roles in asp.net mvc

25,843

Solution 1

using the link shared by @VikasRana http://www.codeproject.com/Articles/578374/AplusBeginner-splusTutorialplusonplusCustomplusF

I got rid of my enum Role and my method

public CustomAuthorizeAttribute(params object[] roles)
    { ...}

I then changed Role in my model to be a string e.g. User.Role="Admin" instead of int. In my onAuthorization method I changed it to:

` public override void OnAuthorization(AuthorizationContext filterContext)
    {
        base.OnAuthorization(filterContext);
        if (!filterContext.HttpContext.User.Identity.IsAuthenticated)
        {
            filterContext.Controller.TempData["ErrorDetails"] = "You must be logged in to access this page";
            filterContext.Result = new RedirectResult("~/User/Login");
            return;
        }
        if (filterContext.Result is HttpUnauthorizedResult)
        {
            filterContext.Controller.TempData["ErrorDetails"] = "You don't have access rights to this page";
            filterContext.Result = new RedirectResult("~/User/Login");
            return;
        }
        }

and in my global.asax added this.

protected void Application_PostAuthenticateRequest(Object sender, EventArgs e)
    {
        if (FormsAuthentication.CookiesSupported == true && Request.IsAuthenticated== true)
        {
            if (Request.Cookies[FormsAuthentication.FormsCookieName] != null)
            {
                try
                {
                    //let us take out the username now                
                    string username = FormsAuthentication.Decrypt(Request.Cookies[FormsAuthentication.FormsCookieName].Value).Name;
                    string roles = string.Empty;

                    using (GManagerDBEntities db = new GManagerDBEntities())
                    {
                        User user = db.Users.SingleOrDefault(u => u.Username == username);

                        roles = user.Role;
                    }
                    //let us extract the roles from our own custom cookie
                    //Let us set the Pricipal with our user specific details
                    HttpContext.Current.User = new System.Security.Principal.GenericPrincipal(
                      new System.Security.Principal.GenericIdentity(username, "Forms"), roles.Split(';'));
                }
                catch (Exception)
                {
                    //something went wrong
                }
            }
        }
    }   

Above method is not ideal though.It gets run for every simple page request about 3 times or more.

So here is solution 2:better solution Implement a custom role provider since we are already using custom role implementation.Simply follow this linkhttp://techbrij.com/custom-roleprovider-authorization-asp-net-mvc

Solution 2

Thanks Gotalove for this method in Global.asax. Here is some more help for anyone trying to do a custom Forms Authentication (FormsAuthentication, FormsAuthenticationTicket) using entity framework.

Login Controller SetAuthTicket

protected void GetRoles(int UserID)
    {
        var db = new ResearchSurveysEntities();
        string[] getRoles = { };
        try
        {
            var query =

                from p in db.UserProfiles
                join i in db.webpages_UsersInRoles on p.UserId equals i.UserId
                join r in db.webpages_Roles on i.RoleId equals r.RoleId
                where p.UserId == UserID
                select new { p.UserId, r.RoleName };

            if (query.Count() > 0)
            {

                List<string> gRoles = new List<string>();
                foreach (var item in query)
                {
                    gRoles.Add(item.RoleName);
                }
                getRoles = gRoles.ToArray();
            }
            roles = String.Join("|", getRoles);
        }
        catch (Exception ex)
        {
            WebUtilities wu = new WebUtilities();

            wu.NotifyWebmaster(ex.ToString(), "Get roles for AdminUserID: " + UserID.ToString(), string.Empty, "Login Error");


        }
        finally
        {
            db.Dispose();
        }
    }

WebConfig

<authentication mode="Forms">
  <forms loginUrl="~/Account/Login" timeout="2880" />
</authentication>

Global.asax (From above example)

protected void Application_AuthenticateRequest(Object sender, EventArgs e)
    {
        HttpCookie authCookie = Context.Request.Cookies[FormsAuthentication.FormsCookieName];
        if (authCookie == null || authCookie.Value == "")
            return;

        FormsAuthenticationTicket authTicket;
        try
        {
            authTicket = FormsAuthentication.Decrypt(authCookie.Value);
        }
        catch
        {
            return;
        }

        // retrieve roles from UserData
        string[] roles = authTicket.UserData.Split('|');

        if (Context.User != null)
            Context.User = new GenericPrincipal(Context.User.Identity, roles);
    }
Share:
25,843
GotaloveCode
Author by

GotaloveCode

PHP, VB.NET, C#, ASP.NET MVC, Sharepoint Developer, Office 365 MCSA

Updated on April 11, 2020

Comments

  • GotaloveCode
    GotaloveCode about 4 years

    I have created a custom authentication and authorisation for my users.The problem I am facing is how to get mvc to check that role from inside my users table matches the [Authorize(Role)] on my controller so as to set httpauthorised to true.Below is my customauthorise class.

     [AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, Inherited = true, AllowMultiple = true)]
    public class CustomAuthorizeAttribute : AuthorizeAttribute 
    {
        public override void OnAuthorization(AuthorizationContext filterContext)
        {
            base.OnAuthorization(filterContext);
            if (!filterContext.HttpContext.User.Identity.IsAuthenticated)
            {
                filterContext.Controller.TempData["ErrorDetails"] = "You must be logged in to access this page";
                filterContext.Result = new RedirectResult("~/User/Login");
                return;
            }
    
            if (filterContext.HttpContext.Request.IsAuthenticated)
            {
                using (var db = new GManagerDBEntities())
                {
                    var authorizedRoles = (from u in db.Users
                                           where u.Username == filterContext.HttpContext.User.Identity.Name
                                           select u.Role).FirstOrDefault();
                    Roles = String.IsNullOrEmpty(Roles) ? authorizedRoles.ToString() : Roles;
                }
            }
    
            if (filterContext.Result is HttpUnauthorizedResult)
            {
                filterContext.Controller.TempData["ErrorDetails"] = "You do nat have necessary rights to access this page";
                filterContext.Result = new RedirectResult("~/User/Login");
                return;
            }
    
        }
        public CustomAuthorizeAttribute(params object[] roles)
        {
            if (roles.Any(r => r.GetType().BaseType != typeof(Enum)))
                throw new ArgumentException("roles");
    
            this.Roles = string.Join(",", roles.Select(r => Enum.GetName(r.GetType(), r)));
        }
    }
    

    below is my controller with decoration

     [CustomAuthorize(Role.Administrator)]
        [HttpGet]
        public ActionResult CreateEmployees()
        {
            return View();
        }
    

    and my enum for role

    public enum Role
    {
        Administrator = 1,
        UserWithPrivileges = 2,
        User = 3,
    }
    

    and model

    public class UserModel
    {
        public int UserID { get; set; }
        [Required]
        [Display(Name="Username:")]
        public string Username { get; set; }
        [Required]
        public string Password { get; set; }
        public int Role { get; set; }
    }
    

    see pastie for clear view pastie

    links I have viewed in trying to solve this among others but I cant seem to piece it togetherMVC 3 Authorize custom roles http://forums.asp.net/p/1573254/3948388.aspx

    Customized authorization attribute in MVC 4 with Roles