MVC小型商务网站实例(4)--MVC权限管理
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();
}
}
这样就搞定了,对于权限相关的数据表的增、删、改我这里就不废话了。