經過創建本身的AuthorizeAttribute實現網站的權限管理

當咱們用.net MVC構建網站平臺的時候,勢必會對網站平臺的安全性和用戶的使用權限進行一個統一的構建,首先在.net MVC 架構中,系統已經將權限管理分爲三個層面來進行管理,第一層面是 登陸管理,也就是說在這個層面上完成用戶口令的驗證,即完成用戶的登陸,系統保存用戶的登陸記錄。第二層面是受權,即賦予用戶是否具有使用權限,是經過 AuthorizeAttribute 的特性來進行控制和管理的。第三個層面是是憑據緩存機制,系統創建System.Security.Claims.Claim來實現的,一旦登陸成功系統就會在Cookies裏面緩存給用戶一個Claim,這樣完成了用戶登陸信息的緩存。數據庫

那麼若是對某一個模塊具體進行權限控制呢?爲了創建一個更加靈活的管理機制,咱們採用了創建本身的 AuthorizeAttribute 來完成。首先咱們來對需求進行一個簡單的分析,以下圖所示:一個功能模塊咱們能夠經過指定用戶,或指定權限來完成,也可能在使用時,經過角色和權限的控制來完成。c#

也就是說用戶能夠經過用戶,也能夠經過角色來進行控制,也能夠在運行期經過角色和功能模塊的指定來進行。緩存

針對這個需求,咱們創建了以下數據結構:
安全

人員和角色是經過用戶歸屬角色表進行關聯的,而「功能權限控制」是功能直接和用戶仍是角色關聯控制的。數據結構

爲了實現這個功能設計,首先咱們先在Models中創建四個基礎信息類架構

namespace VonPortal.Web.Models
{
    /// <summary>人員基本信息 信息類</summary>
    public class UserInfo : IUser<int>
    {
        public int Id
        {
            get { return ID; }
        }
        #region "Public Properties"
        /// <summary>序號</summary>
        [Required]
        [Display(Name = "序號")]
        public int ID { get; set; }
        /// <summary>登陸名</summary>
        [Required]
        [Display(Name = "登陸名")]
        public string UserName { get; set; }
        /// <summary>姓氏</summary>
        [Display(Name = "姓氏")]
        public string FirstName { get; set; }
        /// <summary>名字</summary>
        [Display(Name = "名字")]
        public string LastName { get; set; }
        /// <summary>顯示名稱</summary>
        [Display(Name = "顯示名稱")]
        public string DisplayName { get; set; }
        /// <summary>稱謂</summary>
        [Display(Name = "稱謂")]
        public string Title { get; set; }
        /// <summary>簡稱</summary>
        [Required]
        [Display(Name = "簡稱")]
        public string ShortName { get; set; }
        /// <summary>電子郵箱</summary>
        [Required]
        [Display(Name = "電子郵箱")]
        public string EMail { get; set; }
        /// <summary>登陸口令</summary>
        [Display(Name = "登陸口令")]
        public string Password { get { return _Password; } set { _Password = UserCtrl.CryptPassword(value); } }
        internal string _Password = "";
        /// <summary>建立時間</summary>
        [Display(Name = "建立時間")]
        public DateTime CreateDate { get; set; }
        /// <summary>最後訪問時間</summary>
        [Display(Name = "最後訪問時間")]
        public DateTime LastAccess { get; set; }
        #endregion
    }
}
#region "角色信息信息類聲明"
namespace VonPortal.Web.Models
{
    /// <summary>角色信息 信息類</summary>
    public class RoleInfo : IRole<int>
    {
        public int Id
        {
            get
            {
                return ID;
            }
        }

        public string Name
        {
            get
            {
                return RoleName;
            }

            set
            {
                RoleName = value;
            }
        }
        #region "Constructors"
        /// <summary>
        /// 構造函數
        /// </summary>
        public RoleInfo()
        {
        }
        /// <summary>
        /// 含初始化構造函數
        /// </summary>
        /// <param name="ID">序號</param>
        /// <param name="GroupName">組名稱</param>
        /// <param name="RoleName">角色名稱</param>
        /// <param name="SiteIdx">站點序號</param>
        /// <param name="ParentIdx">上級節點</param>
        /// <param name="InheritKind">繼承關係</param>
        /// <param name="Description">角色說明</param>
        public RoleInfo(int ID, string GroupName, string RoleName, int SiteIdx, int ParentIdx, int InheritKind, string Description)
        {
            this.ID = ID;
            this.GroupName = GroupName;
            this.RoleName = RoleName;
            this.SiteIdx = SiteIdx;
            this.ParentIdx = ParentIdx;
            this.InheritKind = InheritKind;
            this.Description = Description;
        }
        #endregion
        #region "Public Properties"
        /// <summary>序號</summary>
        [Required]
        [Display(Name = "序號")]
        public int ID { get; set; }
        /// <summary>組名稱</summary>
        [Display(Name = "組名稱")]
        public string GroupName { get; set; }
        /// <summary>角色名稱</summary>
        [Display(Name = "角色名稱")]
        public string RoleName { get; set; }
        /// <summary>站點序號</summary>
        [Required]
        [Display(Name = "站點序號")]
        public int SiteIdx { get; set; }
        /// <summary>上級節點</summary>
        [Required]
        [Display(Name = "上級節點")]
        public int ParentIdx { get; set; }
        /// <summary>繼承關係</summary>
        [Display(Name = "繼承關係")]
        public int InheritKind { get; set; }
        /// <summary>角色說明</summary>
        [Display(Name = "角色說明")]
        public string Description { get; set; }

        #endregion
    }
}
#endregion
//功能權限控制(PTL_ActionRight)
#region "功能權限控制信息類聲明"
namespace VonPortal.Web.Models
{
    /// <summary>功能權限控制 信息類</summary>
    public class ActionRightInfo
    {
        #region "Constructors"
        /// <summary>
        /// 構造函數
        /// </summary>
        public ActionRightInfo()
        {
        }
        /// <summary>
        /// 含初始化構造函數
        /// </summary>
        /// <param name="ID">序號</param>
        /// <param name="SiteIdx">站點序號</param>
        /// <param name="RightName">功能名稱</param>
        /// <param name="RoleOrUser">角色或用戶序號</param>
        /// <param name="SrcIdx">控制源序號</param>
        public ActionRightInfo(int ID, int SiteIdx, string RightName, bool RoleOrUser, int SrcIdx)
        {
            this.ID = ID;
            this.SiteIdx = SiteIdx;
            this.RightName = RightName;
            this.RoleOrUser = RoleOrUser;
            this.SrcIdx = SrcIdx;
        }
        #endregion
        #region "Public Properties"
        /// <summary>序號</summary>
        [Required]
        [Display(Name = "序號")]
        public int ID { get; set; }
        /// <summary>站點序號</summary>
        [Required]
        [Display(Name = "站點序號")]
        public int SiteIdx { get; set; }
        /// <summary>功能名稱</summary>
        [Display(Name = "功能名稱")]
        public string RightName { get; set; }
        /// <summary>角色或用戶序號</summary>
        [Required]
        [Display(Name = "角色或用戶序號")]
        public bool RoleOrUser { get; set; }
        /// <summary>控制源序號</summary>
        [Required]
        [Display(Name = "控制源序號")]
        public int SrcIdx { get; set; }
        #endregion
    }
}
#endregion

其控制與數據庫存儲的類,這裏就省略了,首先你們知道,要實現這個方案,做爲基礎的信息基類,就是這三個類即,UserInfo、RoleInfo、ActionRightInfo。ide

咱們下面就進入今天的主題,如何經過創建本身的AuthorizeAttribute特性來實現角色控制。函數

咱們先來分析一下AuthorizeAttribute的執行過程。在特性指定到系統的某一個模塊上時,即爲某一個 Controller 指定一個咱們本身的權限認證特性,指定後,當系統執行時,系統就會調用 AuthorizeAttribute 中的 OnAuthorization 函數來完成,在 OnAuthorization 函數的執行過程當中,系統會調用 bool AuthorizeCore(HttpContextBase httpContext) 函數完成具體的驗證過程,若是失敗了,系統會調用 void HandleUnauthorizedRequest(AuthorizationContext context)來進行處理,由此咱們就能夠創建一個本身的 AuthorizeAttribute 網站

/******************************************************************************************************************
* 權限驗證單元
*   RightAuthorizeAttribute 是繼承 AuthorizeAttribute 的權限控制屬性,他是基於功能的權限認證模式,即採用功能名稱
*   進行認證,認證過程基於 AuthorizeAttribute 進行,首先系統會調用 OnAuthorization 進行驗證,在這裏咱們主要進行
*   驗證前準備,
****************************************************************************************************************/
using System;
using System.Threading.Tasks;
using Microsoft.AspNet.Identity;
using Microsoft.AspNet.Identity.Owin;
using Microsoft.Owin.Security;
using System.Web.Mvc;
using System.Web.Routing;
using System.Web;
using System.Collections.Generic;
using VonPortal.Web.Operators;

namespace VonPortal.Web.Models
{
    /// <summary>
    /// 權限控制單元
    /// </summary>
    public class RightAuthorizeAttribute : AuthorizeAttribute
    {
        /// <summary>
        /// 功能名稱
        /// </summary>
        public string ActionNames { get; set; }
        private string moduleName = "";
        public override void OnAuthorization(AuthorizationContext filterContext)
        {
            string controllerName = filterContext.ActionDescriptor.ControllerDescriptor.ControllerName;
            string actionName = filterContext.ActionDescriptor.ActionName;
            moduleName = controllerName + '/' + actionName;
            base.OnAuthorization(filterContext);
        }
        protected override bool AuthorizeCore(HttpContextBase httpContext)
        {
            bool result = false;
            if (httpContext == null)
                throw new ArgumentNullException("HttpContext");
            if (!httpContext.User.Identity.IsAuthenticated)
                return false;
            // 獲得用戶的惟一序號
            int userIdx = httpContext.User.Identity.GetUserId<int>();
            List<int> roles = (new UserRoleCtrl(null)).ListByROLE_REF_USER(userIdx);
            #region "檢測 Roles 即,檢測指定的 Role 是否存在,若是設定了,但不存在則代表無權訪問。"
            if (Roles != null && Roles.Length > 0)
            {
                string authRole = "," + Roles.ToLower() + ",";
                result = false;
                foreach (int roleIdx in roles)
                {
                    RoleInfo role = (new RoleCtrl(null)).GetByRole(roleIdx);
                    result = role != null && authRole.IndexOf("," + role.RoleName.ToLower() + ",") >= 0;
                    if (result) break;
                }
                if (!result) return false;
            }
            #endregion
            #region "檢測 Users 即,檢測指定的 Users 是否存在,若是設定了,但不存在則代表無權訪問。"
            string userName = httpContext.User.Identity.GetUserName();
            if (Users != null && Users.Length > 0)
            {
                if (("," + Users.ToLower() + ",").IndexOf("," + userName.ToLower() + ",") < 0)
                    return false;
                result = true;
            }
            #endregion
            #region "檢測 ActionNames 即,檢測指定的 ActionNames 是否存在,若是設定了,但不存在則代表無權訪問。"
            if (ActionNames != null && ActionNames.Length > 0)
            {
                string authAction = "," + ActionNames.ToLower() + ","; 
                // 檢測用戶自己是否具有該功能的權限
                foreach (ActionRightInfo right in (new ActionRightCtrl(null)).ListBySrcIdx(true, userIdx))
                {
                    if (ActionNames.IndexOf("," + right.RightName + ",") >= 0) return true;
                }
                // 檢測用戶擁有的角色自己是否具有該功能的權限
                foreach (int roleIdx in roles)
                {
                    foreach (ActionRightInfo right in (new ActionRightCtrl(null)).ListBySrcIdx(false, roleIdx))
                    {
                        if (ActionNames.IndexOf("," + right.RightName + ",") >= 0) return true;
                    }
                }
            }
            else if (!result)
            {
                string authAction = "," + moduleName.ToLower() + ",";
                // 檢測用戶自己是否具有該功能的權限
                foreach (ActionRightInfo right in (new ActionRightCtrl(null)).ListBySrcIdx(true, userIdx))
                {
                    if (ActionNames.IndexOf("," + right.RightName + ",") >= 0) return true;
                }
                // 檢測用戶擁有的角色自己是否具有該功能的權限
                foreach (int roleIdx in roles)
                {
                    foreach (ActionRightInfo right in (new ActionRightCtrl(null)).ListBySrcIdx(false, roleIdx))
                    {
                        if (ActionNames.IndexOf("," + right.RightName + ",") >= 0) return true;
                    }
                }
            }
            #endregion
            return result;
        }
        protected override void HandleUnauthorizedRequest(AuthorizationContext context)
        {
            if (context == null)
            {
                throw new ArgumentNullException("filterContext");
            }
            else
            {
                string path = context.HttpContext.Request.Path;
                string strUrl = "/Account/Login?returnUrl={0}";
                context.HttpContext.Response.Redirect(string.Format(strUrl, HttpUtility.UrlEncode(path)), true);
            }
        }
    }
}

使用方法:ui

在Controller中的Action使用前增長咱們的RightAuthorize的特性就能夠了。

一、指定功能名稱驗證用戶權限:

        [RightAuthorize(ActionNames = "UserManager")]

        public ActionResult UserList(...){...}

二、指定角色名稱證用戶權限:

        [RightAuthorize(Roles = "Admin")]

        public ActionResult UserDetails(...){...}

三、指定用戶名稱證用戶權限:

        [RightAuthorize(Users = "Administrator,Host")]

        public ActionResult UserEdit(...){...}

四、默認經過Controller+Action來驗證用戶權限:默認的功能名稱是ControllerName/ActionName

        [RightAuthorize()]

        public ActionResult UserDelete(...){...}

相關文章
相關標籤/搜索