ASP.NET MVC許可權管理相關的文章實在太少了,真正在項目開發中實用的那就更少了。可能是大家都用Webform做後台開發吧。
轉入正題:
模組實現功能:
角色管理
– 角色的增、刪、改
,給角色綁定使用者和取消綁定
存取權限管理
– 存取權限的增、刪、改
登入後的存取權限驗證
表設計圖:
ControllerAction 存放的是要設定存取權限的Controller和Action,ControllerActionRole
存放的是對應的角色可訪問的Controller和Action,其它的表就不用多說了。
表的關聯概述:
使用者角色表(UserRole)在使用者表(Use)與角色表(Role)中啟串連綁定的關係,是一對多的一個使用者只能有一個角色。
角色存取權限表(ControllerActionRole)在角色表(Role)與存取權限表(ControllerAction)中也是啟串連綁定的關係,是一對多的,一個角色可以有多個存取權限。
設計思路:
使用者登入時從資料庫中取得對應角色用Session儲存,再用Filter來驗證使用者的存取權限。為了提高效率可以把與存取權限相關的資料緩衝起來。
實現代碼:
先寫一個存取權限的判斷的Service
public static class AccountService
{
private static SouthShopEntities1 Service { get { return BaseRepository.sse; } }
private static IMsCache MsCache { get { return (IMsCache)MvcApplication.Container["msCache"]; } }
public static bool IsAllowed(Role role, string controllerName, string actionName)
{
IEnumerable<ControllerAction> cas;
if (!MsCache.TryGet("ControllerActions", out cas))
{
try
{
cas = Service.ControllerActions.ToList();
var _ExpireTime = DateTime.Now.AddMinutes(30);//指定30分鐘後到期
MsCache.Set<IEnumerable<ControllerAction>>("ControllerActions", cas, _ExpireTime);
}
catch (Exception e)
{
throw new Exception(e.Message);
}
}
// 擷取對應的controller
var controller = (cas.Where(c => c.Name == controllerName)).Where(c => c.IsControler).Select(c => c).FirstOrDefault();
if (controller != null)
{
// 擷取對應的action
var controllerAction = ((cas.Where(c => c.Name == actionName)).Where(c => c.IsControler == false)).Where(c => c.ControlerName == controllerName).Select(c => c).FirstOrDefault();
return controllerAction == null ? IsAllowed(role, controller) : IsAllowed(role, controllerAction);
}
return false;
}
public static bool IsAllowed(Role role, ControllerAction controllerAction)
{
IEnumerable<ControllerActionRole> cars;
string userCAR = role.RoleId + "_ControllerActionRole";
if (!MsCache.TryGet(userCAR, out cars))
{
try
{
cars = Service.ControllerActionRoles.Where(c => c.RoleId == role.RoleId).Select(c => c).ToList();
var _ExpireTime = DateTime.Now.AddMinutes(30);//指定30分鐘後到期
MsCache.Set<IEnumerable<ControllerActionRole>>(userCAR, cars, _ExpireTime);
}
catch (Exception e)
{
throw new Exception(e.Message);
}
}
// 允許沒有角色的:也就是說允許所有人,包括沒有登入的使用者
if (controllerAction.IsAllowedNoneRoles)
{
return true;
}
// 允許所有角色:只要有角色,就可以訪問
if (controllerAction.IsAllowedAllRoles)
{
if (role == null)
{
return false;
}
return true;
}
// 選出action對應的角色
var roles = cars.Where(c=>c.ControlerActionId==controllerAction.ControllerActionId).Select(c=>c).ToList();
if (roles.Count == 0)
{
// 角色數量為0,也就是說沒有定義訪問規則,預設允許訪問
return true;
}
//尋找有沒有目前使用者所對應的角色
var HavedRolesids = roles.Find(c=>c.RoleId==role.RoleId);
if (HavedRolesids == null)
{
//找不到目前使用者所對應的角色,不允許訪問
return false;
}
//只有允許旂角色才可以訪問
if (HavedRolesids.IsAllowed)
{
return true;
}
return false;
}
}
再實現存取權限的Filter ,在裡面調用上面的Service。
public class RoleAuthorizeAttribute : AuthorizeAttribute
{
public override void OnAuthorization(AuthorizationContext filterContext)
{
bool isAllowed = false;
var role = filterContext.HttpContext.Session["CurrentRole"] as Role;
var controller = filterContext.RouteData.Values["controller"].ToString();
var action = filterContext.RouteData.Values["action"].ToString();
if (role != null)
isAllowed = AccountService.IsAllowed(role, controller, action);
if (!isAllowed)
{
filterContext.RequestContext.HttpContext.Response.Write("無權訪問");
filterContext.RequestContext.HttpContext.Response.End();
}
}
}
如果是整個Controller下都需要身分識別驗證的話,那就把這個Filter放到外層的Controller上。這樣就不用在每個Action上都寫了。如:
[RoleAuthorize]
public class AdminController : Controller
{
public ActionResult Index()
{
return View();
}
}
這樣就搞定了,對於許可權相關的資料表的增、刪、改我這裡就不廢話了。