asp.net MVC 許可權設計
幾點說明: 1、該許可權系統是個網站用的,使用者簡單,因此不涉及到部門這些資訊 2、基於將角色與controller、action相關聯來判斷使用者是否有權 3、通過過載AuthorizeAttribute實現 資料庫設計:
表說明
ControllerAction
- Name是controller的名稱
- IsController是指是否是controller,如果為false,表示存的是action,那麼controllerName欄位就派上用場了
- IsAllowedNoneRoles是指是否允許沒有許可權的人訪問
- IsAllowedAllRoles是指是否允許有角色的人訪問
IsAllowedNoneRoles,IsAllowedAllRoles實現了允許所有人訪問以及允許所有註冊使用者訪問:),並且我們約定,IsAllowedNoneRoles具有最高的優先順序,其次是IsAllowedAllRoles,然後才是ControllerActionRole中定義的規則
ControllerActionRole
IsAllowed表示該action或者controller是否允許訪問,加入表中有兩條記錄 角色 Name ControllName IsAllowed IsController A Admin Home false false A Home Null true true 這裡約定分兩個層次來判斷許可權: 第一條記錄:表示A角色不能訪問 Home/admin 第二條記錄:表示A角色可以訪問Controller下的所有方法 到底能不能訪問呢?其實,我們以action為準,如果定義了action,我們直接從action的約定來判斷,因此這裡判斷A不能訪問Home/admin
其他幾張表一看就明白,不再多說
判斷是否有許可權的設定
1、獲取controller,action,以及存放在session中的使用者資訊
1 publicclass UserAuthorizeAttribute : AuthorizeAttribute 2 { 3 4 publicoverridevoid OnAuthorization(AuthorizationContext filterContext) 5 { 6 var user = filterContext.HttpContext.Session["CurrentUser"] as User; 7 var controller = filterContext.RouteData.Values["controller"].ToString(); 8 var action = filterContext.RouteData.Values["action"].ToString(); 9 var isAllowed =this.IsAllowed(user, controller, action); 10 11 if (!isAllowed) 12 { 13 filterContext.RequestContext.HttpContext.Response.Write("無權訪問"); 14 filterContext.RequestContext.HttpContext.Response.End(); 15 } 16 17 } 18 19 …… 20 21 } 22
2、檢索資料庫ControllerAction表中有沒有Name為第一步中controller 的記錄,如果沒有,我們約定這個controller是不需要進行許可權控制的,如果有的話,進入第三步
3、前面提到了,我們約定對許可權的控制分為兩個層次,controller和action層次,如果同時定義了,以action為準。因此,我們需要判斷是否在資料庫中有action的記錄,如果有,進入4,無,進入5
1 bool IsAllowed(User user, string controllerName, string actionName)
2 {
3 var service = ServiceLoader.LoadService<ToySpirit.IToySpiritService.IControllerActionService>();
4
5 // 獲取對應的controller
6 var controller = service.GetSingleByExpression(c => c.Name == controllerName && c.IsController);
7 if (controller !=null)
8 {
9 // 獲取對應的action
10 var controllerAction = service.GetSingleByFunc(c => c.Name == actionName && c.IsController ==false&& c.ControllerName == controllerName);
11
12 return controllerAction ==null?this.isAllowed(user, controller) : this.isAllowed(user, controllerAction);
13 }
14
15 // 沒有定義controller的許可權,表示無需許可權控制
16 returntrue;
17 }
18
19
4、如果有action的記錄,那麼我們首先判斷controllerAction 拒絕哪些角色訪問,如果使用者有角色在這裡面,很遺憾,就不能訪問了;然後判斷controllerAction 允許哪些角色訪問,如果使用者的角色在這裡面,就可以訪問了
注:這裡很有可能使用者有多個角色,比如A,B,C,如果A不能訪問controllerAction,那麼很遺憾,使用者不能訪問,儘管角色B,C可能可以訪問該controllerAction
5、沒有action的記錄,自然就檢查controller對應的controllerAction 了
程式碼
4、5判斷的程式碼是一樣的,如下:
privatebool isAllowed(User user, ControllerAction controllerAction)
{
// 允許沒有角色的:也就是說允許所有人,包括沒有登入的使用者
if (controllerAction.IsAllowedNoneRoles)
{
returntrue;
}
// 允許所有角色:只要有角色,就可以訪問
if (controllerAction.IsAllowedAllRoles)
{
return user.Roles.Count >0;
}
if (user ==null|| user.Roles.Count ==0)
{
returnfalse;
}
// 選出action對應的角色
var roles = controllerAction.ControllerActionRoles.Select(ca => ca.Role).ToList();
if (roles.Count ==0)
{
// 角色數量為0,也就是說沒有定義訪問規則,預設允許訪問
returntrue;
}
var userHavedRolesids = user.Roles.Select(r => r.ID).ToList();
// 查詢禁止的角色
var notAllowedRoles = controllerAction.ControllerActionRoles.FindAll(r => r.IsAllowed ==false).Select(ca => ca.Role).ToList();
if (notAllowedRoles.Count >0)
{
foreach (Role role in notAllowedRoles)
{
// 使用者的角色在禁止訪問列表中,不允許訪問
if (userHavedRolesids.Contains(role.ID))
{
returnfalse;
}
}
}
// 查詢允許訪問的角色列表
var allowRoles = controllerAction.ControllerActionRoles.FindAll(r => r.IsAllowed).Select(ca => ca.Role).ToList();
if (allowRoles.Count >0)
{
foreach (Role role in allowRoles)
{
// 使用者的角色在訪問的角色列表
if (userHavedRolesids.Contains(role.ID))
{
returntrue;
}
}
}
returnfalse;
}
使用方法:
建立一個basecontroller,使用我們定義好的UserAuthorize,然後所有的controller繼承basecontroller就可以了
1 ///<summary>
2 /// 控制基類
3 ///</summary>
4 [UserAuthorize]
5 publicabstractclass BaseController : Controller
6 {}
7
8 publicclass HomeController : BaseController{}
9
演示:
在controlleraction中新增幾條資料:
根據我們的規則,我們可以知道,未登入的使用者可以訪問Home/Public,其他幾個頁面則不能訪問
我們看對應的Action:
1 publicvoid ViewPage()
2 {
3 Response.Write("View");
4 }
5 publicvoid Public()
6 {
7 Response.Write("Public");
8 }
9 publicvoid Delete()
10 {
11 Response.Write("Delete");
12 }
訪問Home/Public,如果有許可權,那麼顯示“Public“,否則顯示”無權訪問”
未登入使用者訪問Home/Public,結果符合我們的約定;-)
未登入使用者訪問Home/ViewPage,按約定應該顯示錯誤資訊