ASP.NET MVC5+EF6+EasyUI 後臺管理系統(21)-權限管理系統-跑通整個系統

系列目錄html

這一節咱們來跑通整個系統,驗證的流程,經過AOP切入方式,在訪問方法以前,執行一個驗證機制來判斷是否有操做權限(如:增刪改等)數據庫

原理:經過MVC自帶篩選器,在篩選器分解路由的Action和controller來驗證是否有權限。編程

首先咱們要理解一下篩選器緩存

篩選器的由來及用途
有時,您須要在調用操做方法以前或運行操做方法以後執行邏輯。安全

爲了對此提供支持,ASP.NET MVC 提供了篩選器。 篩選器是自定義類,可提供用於向控制器操做方法添加操做前行爲和操做後行爲的聲明性和編程性手段。session

ASP.NET MVC 支持如下類型的操做篩選器:框架

受權篩選器。 這些篩選器用於實現 IAuthorizationFilter 和作出關因而否執行操做方法(如執行身份驗證或驗證請求的屬性)的安全決策。 AuthorizeAttribute 類和 RequireHttpsAttribute 類是受權篩選器的示例。 受權篩選器在任何其餘篩選器以前運行。ide

操做篩選器。 這些篩選器用於實現 IActionFilter 以及包裝操做方法執行。 IActionFilter 接口聲明兩個方法:OnActionExecuting 和 OnActionExecuted。 OnActionExecuting 在操做方法以前運行。 OnActionExecuted 在操做方法以後運行,能夠執行其餘處理,如向操做方法提供額外數據、檢查返回值或取消執行操做方法。測試

結果篩選器。 這些篩選器用於實現 IResultFilter 以及包裝 ActionResult 對象的執行。 IResultFilter 聲明兩個方法:OnResultExecuting 和 OnResultExecuted。 OnResultExecuting 在執行 ActionResult 對象以前運行。 OnResultExecuted 在結果以後運行,能夠對結果執行其餘處理,如修改 HTTP 響應。 OutputCacheAttribute 類是結果篩選器的一個示例。ui

異常篩選器。 這些篩選器用於實現 IExceptionFilter,並在 ASP.NET MVC 管道執行期間引起了未處理的異常時執行。 異常篩選器可用於執行諸如日誌記錄或顯示錯誤頁之類的任務。 HandleErrorAttribute 類是異常篩選器的一個示例。

建立自定義操做篩選器

框架將先調用操做篩選器的 OnActionExecuting 方法,而後再調用以操做篩選器特性標記的任意操做方法。 一樣,該框架將在操做方法完成後調用 OnActionExecuted 方法。

調用 OnResultExecuting 方法後,要當即調用您的操做返回的 ActionResult 實例。 執行結果後,緊接着就要調用 OnResultExecuted 方法。 這些方法對於執行日誌記錄、緩存輸出結果之類的操做很是有用。

以上都是理論問題了,說到底咱們就是要OnActionExecuting利用這個方法

當一個Action被執行時調用OnActionExecuting判斷是否有權限操做。

因爲OnActionExecuting涉及到其餘用戶和權限的訪問咱們須要添加SysUser和SysRight的BLL和DAL層了

咱們還須要一個存儲過程[P_Sys_GetRightOperate]用於取模塊的當前用戶操做權限,這裏爲何用存儲過程呢,快點唄,反正這快不用怎麼維護了

存儲過程以下:

USE db
GO

/****** Object:  StoredProcedure [dbo].[P_Sys_GetRightOperate]    Script Date: 12/01/2013 12:25:48 ******/
SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

-- =============================================
-- Author:        <Author,,Name>
-- Create date: <Create Date,,>
-- Description:    <Description,,>
-- =============================================
CREATE PROCEDURE [dbo].[P_Sys_GetRightOperate]
@userId varchar(50),@url varchar(200)
AS
--取模塊的當前用戶操做權限
select distinct KeyCode,IsValid from SysRightOperate where RightId in(
select a.id from SysRight a, SysModule b where RoleId in(
    select SysRoleId from SysRoleSysUser where SysUserId =@userId)
    and a.ModuleId = b.Id
    and b.Url =@url)
    and IsValid=1


GO
View Code

建立好了把存儲過程更新到EF中去,EF5.0將自動建立一個複雜的類型,你們能夠打開來看下

建立一個權限的類permModel,咱們將獲取到的權限保存到這個類中去,這個類最終是一個一個的session轉換而來的。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace App.Models.Sys
{
    public class permModel
    {
        public string KeyCode { get; set; }//操做碼
        public bool IsValid { get; set; }//是否驗證
    }
}

SysUser的BLL層和SysRight的DAL層了,以下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using App.Models;
using App.Models.Sys;

namespace App.IDAL
{
    public interface ISysRightRepository
    {
        List<permModel> GetPermission(string accountid, string controller);
    }
}
ISysRightRepository
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using App.IDAL;
using App.Models;
using App.Models.Sys;

namespace App.DAL
{
    public class SysRightRepository : ISysRightRepository,IDisposable
    {
     
        /// <summary>
        /// 取角色模塊的操做權限,用於權限控制
        /// </summary>
        /// <param name="accountid">acount Id</param>
        /// <param name="controller">url</param>
        /// <returns></returns>
        public List<permModel> GetPermission(string accountid, string controller) 
        {

            using (DBContainer db = new DBContainer())
            {
                List<permModel> rights = (from r in db.P_Sys_GetRightOperate(accountid, controller)
                                         select new permModel
                                         {
                                             KeyCode = r.KeyCode,
                                             IsValid = r.IsValid
                                         }).ToList();
                return rights;
            }
        }
        public void Dispose()
        { 
            
        }
    }
}
SysRightRepository

GetPermission將經過存儲過程訪問取得數據

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using App.Models.Sys;
using App.Common;
using App.Models;

namespace App.IBLL
{
    public interface ISysUserBLL
    {
        List<permModel> GetPermission(string accountid, string controller);
      
    }
}
ISysUserBLL
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using App.BLL.Core;
using App.IBLL;
using Microsoft.Practices.Unity;
using App.IDAL;
using App.Models.Sys;
using App.Common;
using App.Models;
using System.Transactions;
namespace App.BLL
{
    public class SysUserBLL : BaseBLL,  ISysUserBLL
    {
        [Dependency]
        public ISysRightRepository sysRightRepository { get; set; }
        public List<permModel> GetPermission(string accountid, string controller)
        {
            return sysRightRepository.GetPermission(accountid,controller);
        }


    }
}
SysUserBLL

能夠把SysRightRepository變成SysUserRepository層,我這樣作是爲了區分一下而已,SysRight表明權限,SysUser是用戶,根據不一樣的用戶獲取他的權限

咱們建立一個篩選器在App.Admin下的Core建立SupportFilter.cs

 添加以下代碼:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
using App.Models.Sys;
using App.BLL;
using App.DAL;

namespace App.Admin
{
    public class SupportFilterAttribute : ActionFilterAttribute
    {
        public string ActionName { get; set; }
        private string Area;
        public override void OnActionExecuted(ActionExecutedContext filterContext)
        {
            base.OnActionExecuted(filterContext);

        }
        /// <summary>
        /// Action加上[SupportFilter]在執行actin以前執行如下代碼,經過[SupportFilter(ActionName="Index")]指定參數
        /// </summary>
        /// <param name="filterContext">頁面傳過來的上下文</param>
        public override void OnActionExecuting(ActionExecutingContext filterContext)
        {
            //讀取請求上下文中的Controller,Action,Id
            var routes = new RouteCollection();
            RouteConfig.RegisterRoutes(routes);
            RouteData routeData = routes.GetRouteData(filterContext.HttpContext);
            //取出區域的控制器Action,id
            string ctlName = filterContext.Controller.ToString();
            string[] routeInfo = ctlName.Split('.');
            string controller = null;
            string action = null;
            string id = null;

            int iAreas = Array.IndexOf(routeInfo, "Areas");
            if (iAreas > 0)
            {
                //取區域及控制器
                Area = routeInfo[iAreas + 1];
            }
            int ctlIndex = Array.IndexOf(routeInfo, "Controllers");
            ctlIndex++;
            controller = routeInfo[ctlIndex].Replace("Controller", "").ToLower();

            string url = HttpContext.Current.Request.Url.ToString().ToLower();
            string[] urlArray = url.Split('/');
            int urlCtlIndex = Array.IndexOf(urlArray, controller);
            urlCtlIndex++;
            if (urlArray.Count() > urlCtlIndex)
            {
                action = urlArray[urlCtlIndex];
            }
            urlCtlIndex++;
            if (urlArray.Count() > urlCtlIndex)
            {
                id = urlArray[urlCtlIndex];
            }
            //url
            action = string.IsNullOrEmpty(action) ? "Index" : action;
            int actionIndex = action.IndexOf("?", 0);
            if (actionIndex > 1)
            {
                action = action.Substring(0, actionIndex);
            }
            id = string.IsNullOrEmpty(id) ? "" : id;

            //URL路徑
            string filePath = HttpContext.Current.Request.FilePath;
            AccountModel account = filterContext.HttpContext.Session["Account"] as AccountModel;
            if (ValiddatePermission(account, controller, action, filePath))
            {
                return;
            }
            else
            {
                filterContext.Result = new EmptyResult();
                return;
            }
        }
        public bool ValiddatePermission(AccountModel account, string controller, string action, string filePath)
        {
            bool bResult = false;
            string actionName = string.IsNullOrEmpty(ActionName) ? action : ActionName;
            if (account != null)
            {
                List<permModel> perm = null;
                //測試當前controller是否已賦權限值,若是沒有從
                //若是存在區域,Seesion保存(區域+控制器)
                if (!string.IsNullOrEmpty(Area))
                {
                    controller = Area + "/" + controller;
                }
                perm = (List<permModel>)HttpContext.Current.Session[filePath];
                if (perm == null)
                {
                    using (SysUserBLL userBLL = new SysUserBLL()
                    {
                        sysRightRepository = new SysRightRepository()
                    })
                    {
                        perm = userBLL.GetPermission(account.Id, controller);//獲取當前用戶的權限列表
                        HttpContext.Current.Session[filePath] = perm;//獲取的勸降放入會話由Controller調用
                    }
                }
                //當用戶訪問index時,只要權限>0就能夠訪問
                if (actionName.ToLower() == "index")
                {
                    if (perm.Count > 0)
                    {
                        return true;
                    }
                }
                //查詢當前Action 是否有操做權限,大於0表示有,不然沒有
                int count = perm.Where(a => a.KeyCode.ToLower() == actionName.ToLower()).Count();
                if (count > 0)
                {
                    bResult = true;
                }
                else
                {
                    bResult = false;
                    HttpContext.Current.Response.Write("你沒有操做權限,請聯繫管理員!");
                }

            }
            return bResult;
        }
        public override void OnResultExecuted(ResultExecutedContext filterContext)
        {
            base.OnResultExecuted(filterContext);
        }
        public override void OnResultExecuting(ResultExecutingContext filterContext)
        {
            base.OnResultExecuting(filterContext);
        }
    }


}

 

這是一個篩選器。全部邏輯代碼都在這裏了
打開SysSampleController

修改Create方法變爲如下

[SupportFilter]
public ActionResult Create()
{
     return View();
}

回到篩選器public string ActionName { get; set; },其中ActionName是自定義Action的名稱,好比在Create中直接[SupportFilter]那麼ActionName取得就是Create,這將和你的數據庫操做碼進行對應的,那麼個人方法是CreateAttr,那麼要使用Create這個操做碼,怎麼辦
那麼就是

[SupportFilter(ActionName = "Create")]
public ActionResult CreateAttr()

 那麼相似的寫法

[SupportFilter(ActionName = "Index")]
public JsonResult GetList()

Index無需填寫操做碼將自動建立操做碼,若是你擁有一個操做碼那麼index將被受權,這個是咱們與系統之間的一個約定(你能夠去掉這個約定,修改代碼便可)
假如你擁有增刪改權限卻沒有訪問列表的權限,那不是...
OnActionExecuting負責分解,交給ValiddatePermission去生成權限
若是寫在Areas區域的也是兼容的,已經作了處理。
若是你越權操做那麼將執行 HttpContext.Current.Response.Write("你沒有操做權限,請聯繫管理員!");
目前位置咱們已經跑通了整個系統了,接下來就是自動化的用戶角色之間的受權和模塊的製做了,能跑通,其餘都是很簡單了,對吧
這一章比較複雜,須要對AOP編程,MVC的篩選器,和路由進行了解,才能讀的比較順。
若是你沒有讀懂,那麼代碼敲一遍,那麼你也就差很少知道了
代碼進行了大量的註釋,還不懂那麼留言。
目前爲止,咱們一個基於按鈕級別的權限系統已經所有跑通,如今,能夠建立一些沒有權限的Action來驗證了

我建立:(很明顯咱們數據庫沒有這個test的 action的權限),因此你別想越權操做了

 [SupportFilter]
        public ActionResult Test()
        {
            return View();
        }

最後預覽

咱們預覽一個有權限的

感謝你們,花了你寶貴的時間閱讀這一節。

相關文章
相關標籤/搜索