ASP. NET series: RBAC permission design, asp. netrbac

Source: Internet
Author: User

ASP. NET series: RBAC permission design, asp. netrbac

The permission system consists of RBAC model, permission verification, permission management, and interface access control. Existing permission system analysis usually has the following problems:

(1) design ideas without Permissions

It is believed that all systems can use a permission system designed based on Table. In fact, the focus of designing a permission system is to judge the stability of the role and identify the minimum authorization requirements. The stability of the role determines whether the system determines whether to use the role to determine the permission or to introduce the RBAC method. The minimum authorization requirement prevents excessive design resulting in the permission granularity exceeding the authorization requirement.

(2) No independent RBAC model Concept

The object class is used directly to represent the RBAC model. As a result, there should be only a few lines of code and the RBAC model that can be reused at the project level cannot be reused, the User, Role, Permission, and other entity classes are required for each project. Furthermore, the structure and Association of the data tables corresponding to the entity class are considered as the core of the Permission system.

(3) Permission abstraction Error

We usually do not implement the operating system or database, although the operating system permissions and database permissions can be used for reference, however, when a business system comes up with a bunch of permissions to add, delete, query, access, and execute such permissions, it is too far away. First, operations at the business level should at least start from the meaning of the business, such as browsing, editing, and review. These customers can easily understand or use words that are more meaningful to customers, what's more, we abstract the permissions from the role according to the minimum authorization requirements. How can we get a bunch of permissions without doing anything.

(4) coupling interface control and permissions

At the beginning, we only had entity Entities, application services, and Interfaces defined by the interface isolation principle, generally, one or more methods in the Service correspond to one permission. At this time, the interface does not exist. Even if there is an interface, it is also a one-way dependency on the interface's permissions, for a system, there may be more than one client type. The access control dependency of each client interface should be stored on the client, moreover, different clients have no way to reuse the data.

Below we use as few code as possible to construct a reusable RBAC model that neither depends on the data access layer nor interface. On this basis, we will summarize the role's stability and permission abstraction.

1. Create An RBAC model

Use POCO to create reusable User, Role, and Permissin models based on RBAC0.

using System.Collections.Generic;namespace RBACExample.RBAC{    public class RBACUser    {        public string UserName { get; set; }        public ICollection<RBACRole> Roles { get; set; } = new List<RBACRole>();    }    public class RBACRole    {        public string RoleName { get; set; }        public ICollection<RBACPermission> Permissions { get; set; } = new List<RBACPermission>();    }    public class RBACPermission    {        public string PermissionName { get; set; }    }}
2. Create a security context

Create a security context RBACContext to set and obtain the RBACUser object. RBACContext uses static variables at the Thread level to save RBACUser objects. It is not responsible for converting object classes to RBAC objects and ensures reusability.

using System;namespace RBACExample.RBAC{    public static class RBACContext    {        [ThreadStatic]        private static RBACUser _User;        private static Func<string, RBACUser> _SetRBACUser;        public static void SetRBACUser(Func<string, RBACUser> setRBACUser)        {            _SetRBACUser = setRBACUser;        }        public static RBACUser GetRBACUser(string username)        {            return _User == null ? (_User = _SetRBACUser(username)) : _User;        }        public static void Clear()        {            _SetRBACUser = null;        }    }}
3. Custom RoleProvider

Custom DelegeteRoleProvider: delegates the specific implementation of GetRolesForUser and IsUserInRole related to permissions to the static proxy to ensure reusability.

using System;using System.Web.Security;namespace RBACExample.RBAC{    public class DelegeteRoleProvider : RoleProvider    {        private static Func<string, string[]> _GetRolesForUser;        private static Func<string, string, bool> _IsUserInRole;        public static void SetGetRolesForUser(Func<string, string[]> getRolesForUser)        {            _GetRolesForUser = getRolesForUser;        }        public static void SetIsUserInRole(Func<string, string, bool> isUserInRole)        {            _IsUserInRole = isUserInRole;        }        public override string[] GetRolesForUser(string username)        {            return _GetRolesForUser(username);        }        public override bool IsUserInRole(string username, string roleName)        {            return _IsUserInRole(username, roleName);        }        #region NotImplemented        #endregion NotImplemented    }}

Configure DelegeteRoleProvider in Web. config

<system.web>    <compilation debug="true" targetFramework="4.5.2"/>    4. Configure RBACContext and DelegeteRoleProvider

Configure the proxy on which RBACContext and DelegeteRoleProvider depend in Application_Start. In order to facilitate the demonstration, we create the RBACUser object directly. Later, we will demonstrate the ing between object classes and RBAC models for different systems.

    public class MvcApplication : System.Web.HttpApplication    {        protected void Application_Start()        {            RBACContext.SetRBACUser(u =>            {                return new RBACUser                {                    UserName = u,                    Roles = new List<RBACRole> {                        new RBACRole                        {                            RoleName="admin",                            Permissions = new List<RBACPermission> {                                new RBACPermission {                                     PermissionName="admin"                                }                            }                        }                    }                };            });            DelegeteRoleProvider.SetGetRolesForUser(userName => RBACContext.GetRBACUser(userName).Roles.SelectMany(o => o.Permissions).Select(p => p.PermissionName).ToArray());            DelegeteRoleProvider.SetIsUserInRole((userName, roleName) => RBACContext.GetRBACUser(userName).Roles.SelectMany(o => o.Permissions).Any(p => p.PermissionName == roleName));            AreaRegistration.RegisterAllAreas();            RouteConfig.RegisterRoutes(RouteTable.Routes);        }    }
5. Use the. net api in ASP. NET MVC

User. IsInRole and AuthorizeAttribute can be used at this time. We have completed an RBAC permission middle layer, which isolates the specific implementation of different systems and does not need to use new API calls. For the service layer, Use Thread. CurrentPrincipal. IsInRole and PrincipalPermissionAttribute.

namespace RBACExample.Controllers{    public class HomeController : Controller    {        public ActionResult Login(string returnUrl)        {            FormsAuthentication.SetAuthCookie("admin", false);            return Redirect(returnUrl);        }        public ActionResult Logoff()        {            FormsAuthentication.SignOut();            return Redirect("/");        }        public ActionResult Index()        {            return Content("home");        }        [Authorize]        public ActionResult Account()        {            return Content(string.Format("user is IsAuthenticated:{0}", User.Identity.IsAuthenticated));        }        [Authorize(Roles = "admin")]        public ActionResult Admin()        {            return Content(string.Format("user is in role admin:{0}", User.IsInRole("admin")));        }    }}
6. Extended AuthorizeAttribute and unified configuration authorization

AuthorizeAttribute is used to distribute authorization across multiple controllers. We can extend AuthorizeAttribute to customize an MvcAuthorizeAttribute and save the configuration in a static dictionary, in this way, the configuration can be read and stored in the dictionary through code, configuration file, or database to achieve dynamic configuration. In this case, you can remove AuthorizeAttribute from the Controller. As described above, the client's Access Control and Permission matching should be stored on the client for the best, even if it is stored in the database, do not associate with permission-related tables.

namespace RBACExample.RBAC{    public class MvcAuthorizeAttribute : AuthorizeAttribute    {        private static Dictionary<string, string> _ActionRoleMapping = new Dictionary<string, string>();        public static void AddConfig(string controllerAction, params string[] roles)        {            var rolesString = string.Empty;            roles.ToList().ForEach(r => rolesString += "," + r);            rolesString = rolesString.TrimStart(',');            _ActionRoleMapping.Add(controllerAction, rolesString);        }        public override void OnAuthorization(AuthorizationContext filterContext)        {            var key = string.Format("{0}{1}", filterContext.ActionDescriptor.ControllerDescriptor.ControllerName, filterContext.ActionDescriptor.ActionName);            if (_ActionRoleMapping.ContainsKey(key))            {                this.Roles = _ActionRoleMapping[key];                base.OnAuthorization(filterContext);            }        }    }}

Use the GlobalFilterCollection configuration to configure MvcAuthorizeAttribute as a global Filter.

         public static void RegisterGlobalFilters(GlobalFilterCollection filters)        {            filters.Add(new HandleErrorAttribute());            MvcAuthorizeAttribute.AddConfig("AccountIndex");            MvcAuthorizeAttribute.AddConfig("AdminIndex", Permission.AdminPermission);            filters.Add(new MvcAuthorizeAttribute());        }
7. Design entity classes as needed

When the RBAC model does not directly rely on entity classes, Entity classes can be designed as needed. You do not need to introduce too many entities to accommodate RBAC associations, so that you can analyze specific problems, no system needs to be mounted to the Role, Permission, and other entity classes. For a Role-stable system, the complexity of the system is reduced, and a large number of background functions are also reduced, it also simplifies operations in the background, and does not require any system to have a permission center that is also difficult for training personnel.

(1) systems that use properties to determine Permissions

Some systems, such as personal blogs, have only one admin role, and the admin role has no stable permissions. Therefore, you do not need to consider using multiple roles or abstract permissions, therefore, User. the IsAdmin attribute can replace Role and Permission. It is unnecessary to use the Role and Permission object classes to increase the amount of code. For permission management in the background, you only need to edit attributes.

              RBACContext.SetRBACUser(u =>            {                var user = new UserEntity { UserName = "admin", IsAdmin = true };                var rbacUser = new RBACUser { UserName = user.UserName };                if (user.IsAdmin)                {                    rbacUser.Roles.Add(new RBACRole                    {                        RoleName = "admin",                        Permissions = new List<RBACPermission> {new RBACPermission {                                     PermissionName="admin"                                } }                    });                }                return rbacUser;            });

(2) systems that use roles to determine Permissions

Some systems, such as B2C marketplace, have multiple roles, but their permissions remain unchanged. Users and Role can be used, and Permission classes are not necessary to apply RBAC, although the Role and Permission allocation and revocation functions are implemented, the Role authorization function of the User is not used. Abstract permissions must meet the authorization requirements. When a role can meet the authorization requirements, the concept of roles and permissions is one. To implement permission management in the background, you only need to manage user roles.

(3) systems requiring dynamic role authorization

Some systems, such as ERP, have multiple unstable roles. Each role usually has multiple permissions. due to changes in the roles and responsibilities of the Organization and personnel, permissions of the roles must be dynamically assigned, A combination of User, Role, and Permission is required. A User has one or more permissions due to different Permission ranges. roles of different users are not parallel but hierarchical. If Permission is not abstracted from Role, A large number of roles need to be defined to correspond to different combinations of permissions. In this case, permission separation makes permission management necessary for the Role. To implement permission management in the background, you need to manage user roles as well as role permissions.

              RBACContext.SetRBACUser(u =>            {                var user = ObjectFactory.GetInstance<IUserService>().GetUserByName(u);                return new RBACUser                {                    UserName = user.UserName,                    Roles = user.Roles.Select(r => new RBACRole                    {                        RoleName = r.RoleName,                        Permissions = r.Permissions.Select(p => new RBACPermission                        {                            PermissionName = p.Name                        }).ToList()                    }).ToList()                };            });
8. Summary

Use RBAC models and. the permission verification API of. NET solves the issue of permission system reuse. Starting from the stability of the role, it prevents the expansion of entity classes. the abstraction of the minimum authorization requirement can prevent the abuse of permissions.

Refer:

(1) https://en.wikipedia.org/wiki/Role-based_access_control

(2) http://csrc.nist.gov/groups/SNS/rbac/faq.html

(3) http://www.codeproject.com/Articles/875547/Custom-Roles-Based-Access-Control-RBAC-in-ASP-NET

(4) http://www.ibm.com/developerworks/cn/java/j-lo-rbacwebsecurity/

Download Demo

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.