Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Custom user authorization based with roles in asp.net mvc

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

like image 678
GotaloveCode Avatar asked Aug 28 '14 12:08

GotaloveCode


People also ask

How do I set an authorized role in MVC?

Create the following database data tables. Open Visual Studio 2015 or an editor of your choice and create a new project. Choose "web application" project and give an appropriate name to your project. Select "empty" template, check on the MVC box, and click OK.

How do you do role based authorization?

For role-based authorization, the customer is responsible for providing the user ID, any optional attributes, and all mandatory user attributes necessary to define the user to Payment Feature Services. The customer must also define the roles that are assigned to the user.


2 Answers

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

like image 167
GotaloveCode Avatar answered Oct 05 '22 04:10

GotaloveCode


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);
    }
like image 25
P.Hoxha Avatar answered Oct 05 '22 03:10

P.Hoxha