Saturday, May 19, 2012

Role management with Windows Authentication

Solution System.Security.Prinicipal.GenericPrincipal class helps you to create a custom principal. It's constructor takes following parameters.
  • IIdentity Identity - Identity of the current user.
  • string[] roles - Array of current user roles.
Steps to create a custom prinicipal class
  1. Create a custom principal by deriving it from GenericPrinicipal class by passing following parameter values to it's constructure.
    Identity : HttpContext.Current.User.Identity .
    Roles : Array of user roles . User roles can be fetched from the DB or from a service.
  2. Implements the IsInRole virtual property with custom logic to check if the current user is in a specific role.
Components of the solutions LoggedInUser - It contains the properties of the user.
UserRole - it is enumeration of all roles available in the application.
CustomPrincipal - The prinicipal class which is inherited from GenericPrinicipal and implements its construction and IsInRole property.
UserContext - Its a facade class that provides the static method GetPrinicipal() which returns a prinicipal object for the current user.
UserHelper - A static helper class with helper methods to obtain prinicipal, user object and user properties.
Code
    public class LoggedInUser
    {
        public int UserId { get; set; }
        public string UserName { get; set; }
        public string DisplayName { get; set; }
        public UserRole Role { get; set; }
        
        public static LoggedInUser Empty = new LoggedInUser()
        {
            UserName = string.Empty,
            DisplayName = string.Empty,
        };

        public bool IsAuthorized
        {
            get
            {
                return this.UserId > 0 && this.Role != UserRole.Undefined;
            }
        }

        public string[] Roles
        {
            get
            {
                return new string[] { this.Role.ToString() };
            }
        }
    }

    public enum UserRole
    {
        Undefined = 0,
        Representative = 1,
        Manager = 2,
        [Description("System Administrator")]
        Administrator = 3,
        Supervisor = 4
    }
    
    public class CustomPrincipal : GenericPrincipal
    {
        #region Data Members
        
        private List _roles;
        private LoggedInUser _user;

        #endregion

        #region Construction

        public CustomPrincipal(IIdentity identity, LoggedInUser user) : this(identity, user.Roles, user)
        {
        }

        public CustomPrincipal(IIdentity identity, IEnumerable roles, LoggedInUser user) : base(identity, roles.ToArray())
        {
            DebugHelper.AssertAndThrow(identity != null, "No identity passed to principal");
            DebugHelper.AssertAndThrow(user != null, "No user data passed to principal");

            _roles = new List(roles);
            _user = user;            
        }

        public static CustomPrincipal Empty = new MatsPrincipal(new GenericIdentity(""), new List(), LoggedInUser.Empty);

        #endregion

        #region Properties

        public string[] Roles { get { return _roles.ToArray(); } }

        public string UserName { get { return _user.UserName; } } 

        public string DisplayName { get { return _user.DisplayName; } }

        public UserRole Role { get { return _user.Role; } }

        public int UserId { get { return _user.UserId; } }

        public bool IsAuthorized { get { return _user.IsAuthorized; } }

        #endregion

        #region Methods

        public bool IsInRole(UserRole role)
        {
            return IsInRole(role.ToString());
        }

        #endregion
    }
    
    public class UserContext
    {
        public static CustomPrincipal GetPrinicipal(string userName)
        {
           var prinicipal = CustomPrincipal.Empty;
           if (string.IsNullOrEmpty(userName))
           {
               return prinicipal;
           }
           var user = userService.GetLoggedInUser(userName);
           prinicpal = new CustomPrinicipal(HttpContext.Current.User.Identity, user);
           return principal;
        }
    }

    public static class UserHelper
    {
        public static CustomPrincipal CurrentUser
        {
            get
            {
                string userName = UserHelper.CurrentUserName;

                return (userName.IsNullOrWhiteSpace()) ?
                    CustomPrincipal.Empty :
                    UserContext.GetPrincipal(userName);
            }
        }
        
        public static string CurrentUserName
        {
            get
            {
                string userName = (HttpContext.Current != null && HttpContext.Current.User != null) ?
                    HttpContext.Current.User.Identity.Name :
                    string.Empty;

                return userName;
            }
        }
        
        public static int CurrentUserId
        {
            get
            {
                return UserHelper.CurrentUser.UserId;
            }
        }

        public static UserRole CurrentUserRole
        {
            get
            {
                return UserHelper.CurrentUser.Role;
            }
        }
    }
    

No comments:

Post a Comment