ASP.NET MVC權限控制思路


在系統開發的時候一個老生常談的權限管理問題,翻閱了很多的網絡資料,但是總感覺離實際使用還有一段距離,其實權限控制無非就幾個“請求、頁面按鈕、字段顯示”, 對於前端權限就需要配合JS了, 這里主要展示我這些年來一直使用的一個關於權限管理的案例,如果你只是寫一個簡單的CMS系統,那么下面代碼其實拷貝就可以用了,如果是需要進行較大型系統開發就需要進一步封裝, 下面是我的思路,寫的不好大家勿噴哈,有不同意見的留下一起探討。

1、在MVC開發時路由中包含了我們所有請求信息(Controller、Action、URL全文),而MVC又提供了過濾器的機制,因此我們將權限管理封裝到過濾其中。首先把每個Controller的繼承封裝一個BaseController,這個Controller基類可以編寫一些直接調用的方法,例如Session等。

    /// <summary>
    /// 系統基礎控制器類
    /// </summary>
    public abstract class BaseUIController : Controller
    {
        /// <summary>
        /// 頁面初始化過程
        /// </summary>
        protected override void Initialize(System.Web.Routing.RequestContext requestContext)
        {
            requestContext.HttpContext.Response.Cache.SetCacheability(HttpCacheability.NoCache);
            base.Initialize(requestContext);
        }

        /// <summary>
        /// 內容返回
        /// </summary>
        /// <param name="content">特定內容供JS參考是否含流程定義等動作。</param>
        /// <param name="contentType"></param>
        /// <param name="contentEncoding"></param>
        /// <returns></returns>
        protected override ContentResult Content(string content, string contentType, Encoding contentEncoding)
        {
            return base.Content(content, contentType, contentEncoding);
        }

        /// <summary>
        /// 登陸用戶ID (Session存儲)
        /// </summary>
        public long LoginedUserID
        {
            get
            {
                object UID = Ant.UI.Controls.SessionConfig.GetSession("UID");
                if (Session == null || UID == null)
                    return -1;
                else
                {
                    return (long)UID;
                }
            }
            set
            {
                Ant.UI.Controls.SessionConfig.SetSession("UID", value);
            }
        }
        
        /// <summary>
        /// 獲取URL參數值,返回 NULL 或 值
        /// </summary>
        /// <param name="keyName">參數名</param>
        public string RequestUrlParams(string keyName)
        {
            if (Array.IndexOf(Request.QueryString.AllKeys, keyName) >= 0)
                return Request.QueryString[keyName].ToString();
            else
                return null;
        }
    }

2、這個時候我們編寫一個過濾器,在這個過濾器中可以在請求的Controller中獲取controller名稱和action名稱。 有了這兩個名稱就能定位到具體的頁面了,當然在得到頁面之前我們可以判斷用戶是否已經登錄。而頁面權限頁已經用數據庫保存起來:A用戶或R角色對某一個Controller/Action的頁面(這個頁面可能是新增信息、修改、刪除信息的請求鏈接)是否有訪問權限。

    /// <summary>
    /// 用戶登錄過濾器
    /// </summary>
    public class UserLoginedFilter : AuthorizeAttribute
    {
        public string name { get; set; }
        /// <summary>
        /// 頁面授權過程(驗證用戶登錄狀態)
        /// </summary>
        /// <param name="filterContext"></param>
        public override void OnAuthorization(AuthorizationContext filterContext)
        {
            UI.Controllers.BaseUIController _ControllerObj = (UI.Controllers.BaseUIController)filterContext.Controller;
            string controllerStr = _ControllerObj.ControllerContext.RouteData.Values["controller"].ToString();
            string actionStr = _ControllerObj.ControllerContext.RouteData.Values["action"].ToString();
            
            //用戶尚未登陸 或 登陸超時。
            if (_ControllerObj.LoginedUserID == -1)
            {
                UserError.LoginError();
            }
            // 權限驗證 根據 Controller 與 Action(這里可以將權限緩存取出來進行用戶匹配,如果被拒絕可以拋出異常)
            else if ( controllerStr.ToLower() == "admin" && actionStr.ToLower() == "login")
            {
                throw new HttpException("權限驗證。" + _ControllerObj.ControllerContext.Controller.ToString());
            }

            base.OnAuthorization(filterContext);
        }
    }

3、此時頁面調用時就不用在每個Action中編寫權限驗證代碼啦(有些權限驗證的源碼會在Action上增加過濾器,為了偷懶硬是想方設法把權限封裝成直接在Controller類上添加一次過濾器就能完成的實現)

    [UserLoginedFilter]
    public class AdminController : UI.Controllers.BaseUIController
    {
        /// <summary>
        /// 登陸(登陸頁面不需要權限驗證,增加AllowAnonymous特性)
        /// </summary>
        [AllowAnonymous]
        public ActionResult Login(FormCollection form)
        {
            return View();
        }

        /// <summary>
        /// 主界面
        /// </summary>
        public ActionResult Index()
        {
            return View();
        }
    }

上面只是我在系統開發過程中對於權限管理的一個思路,也實實在在的應用到了一些系統中,當然上面這些代碼只能勉強判斷是否登陸,如果你需要對數據權限、頁面權限、字段權限進行管理那么就需要進一步的擴展。如果需要在拋出異常后將異常信息友好的返回給客戶端,那你仍然需要在Global中捕獲返回狀態碼以及錯誤信息。因此我說這只是我的一個思路,路過的朋友給我建議。多謝!

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM