html5中文学习网

您的位置: 首页 > 网络编程 > ASP.NET » 正文

Asp.net Mvc4 基于Authorize实现的模块权限验证方式_.NET教程_编程技术

[ ] 已经帮助:人解决问题

在MVC中,我们可以通过在action或者controller上设置Authorize[Role="xxx"] 的方式来设置用户对action的访问权限。显然,这样并不能满足我们的需求,

对于一般的MVC系统来说,如果我们定义一个controller来处理一个模块的话,我们大致有以下需求:

一,单个action的访问权限。如果删除,列表action

二,一个action两种权限,如edit(int? id)如果id为null则添加,或者修改

三,在此cotroller验证其它模块权限,比如,我们要在新闻模块获取新闻列表

四,对于某些通过模块,如分类,我们希望通过传入不同的参数可以验证不同模块的权限

对于四种情况,我理想的想法是:

对于第一种,直接制定controller的moduleid和action的权限

 [Module(ModuleId=6)]
public class Controller: Controller{
        [SysAuthorize(Permission.List)] //设置action要验证的权限
        public ActionResult List()
 }

 

对于第二种情况,我们希望通过参数来达到验证那个权限的目的:

 [Module(ModuleId=6)]
 public class Controller: Controller{
        //如果参数为null是将验证添加权限否则验证修改权限
        [SysAuthorize(Permission.Add,Permission.Edit,"id",null)]      
        public ActionResult Edit(int? id)
  }

 

对于第三种情况,我们可以为action验证指定单独的模块id

    [Module(ModuleId=6)]
    public class Controller: Controller{
        [SysAuthorize(9,Permission.List)] //此方面验证模块9的列表权限
        public ActionResult List(int CType)
    }

 

对于第四种情况,我们可以为模块添加不同的参数module对应关系22gHTML5中文学习网 - HTML5先行者学习网

[Module(ModuleId=5,"CType",1)]    [Module(ModuleId=6,"CType",2)]    public class Controller: Controller{         如果当前传入CType为1则验证ModuleId=5,等于2是验证ModuleId=6        [SysAuthorize(Permission.List)]        public ActionResult List(int CType)    }

想法定好以后,我们就可以去实现了。22gHTML5中文学习网 - HTML5先行者学习网

首先,我们定义一个module的特性:22gHTML5中文学习网 - HTML5先行者学习网

/// <summary>/// 模块信息特性/// </summary>[AttributeUsage(AttributeTargets.Class, Inherited = true, AllowMultiple = true)]public class ModuleAttribute : Attribute{    public ModuleAttribute() { }    public ModuleAttribute(int moduleId)     {        this.ModuleId = moduleId;    }    public ModuleAttribute(int moduleId, string parName, object value)        : this(moduleId)    {        this.ParameterName = parName;        this.ParameterValue = value;    }    /// <summary>    /// 模块Id    /// </summary>    public int ModuleId { get; set; }    /// <summary>    /// 当前模块对应参数名    /// </summary>    public string ParameterName { get; set; }    /// <summary>    /// 当前模块参数值    /// </summary>    public object ParameterValue { get; set; }    /// <summary>    /// 验证参数值是否有正确    /// </summary>    public bool CheckParameter(HttpRequestBase request)    {        var val = request[ParameterName];        bool b = false;        if (val == null && ParameterValue == null)            b = true;        else if (val != null && ParameterValue != null && val == ParameterValue.ToString())            b = true;        return b;    }}

实现了模块特性以后,就是比较重要的验证特性了:22gHTML5中文学习网 - HTML5先行者学习网

/// <summary>/// 系统权限验证/// <remarks>/// 0,只验证登陆:无参数时,只验证登陆/// 1,单一:只一指定权限代码时验证当前模块的指定权限/// 2,二选一:指定两种权限代码时,根据参数验证,如果参数等于指定参数,则验证前者,否则验证后者/// </remarks>/// </summary>[AttributeUsage(AttributeTargets.Class  AttributeTargets.Method, Inherited = true, AllowMultiple = false)]public class SysAuthorizeAttribute : AuthorizeAttribute{    /// <summary>    /// 验证是否登陆    /// </summary>    public SysAuthorizeAttribute() { }    /// <summary>    /// 验证基本权限    /// </summary>    public SysAuthorizeAttribute(Permission permission)    {        this.PermissionFlag = permission;    }    /// <summary>    /// 验证基本权限    /// </summary>    public SysAuthorizeAttribute(int moduleId, Permission permission)        : this(permission)    {        this.ModuleId = moduleId;        this.IsSetModuleId = true;    }    /// <summary>    /// 带参数的验证    /// </summary>    public SysAuthorizeAttribute(Permission permission, string parName, object value = null)    {        this.PermissionFlag = permission;        this.ParameterName = parName;        this.ParameterValue = value;    }    /// <summary>    /// 带参数的验证    /// </summary>    public SysAuthorizeAttribute(int moduleId, Permission permission, string parName, object value = null)        : this(permission, parName, value)    {        this.ModuleId = moduleId;        this.IsSetModuleId = true;    }    /// <summary>    /// 带参数的验证二选一    /// </summary>    public SysAuthorizeAttribute(Permission before, Permission after, string parName, object value = null)    {        this.PermissionFlag = before;        this.PermissionFlag1 = after;        this.ParameterName = parName;        this.ParameterValue = value;    }    /// <summary>    /// 带参数的验证二选一    /// </summary>    public SysAuthorizeAttribute(int moduleId, Permission before, Permission after, string parName, object value = null)        : this(before, after, parName, value)    {        this.ModuleId = moduleId;        this.IsSetModuleId = true;    }    /// <summary>    /// 当前要验证的权限代码    /// </summary>    private Permission? PermissionFlag { get; set; }    /// <summary>    /// 当前要验证的另一个权限代码(当二选一验证验证方式时有效)    /// </summary>    private Permission? PermissionFlag1 { get; set; }    /// <summary>    /// 是否自定义设置了moduleId    /// </summary>    private bool IsSetModuleId { get; set; }    /// <summary>    /// 获取或设置当前模块Id    /// </summary>    public int? ModuleId { get; set; }    /// <summary>    /// 权限验证参数名    /// </summary>    public string ParameterName { get; set; }    /// <summary>    /// 权限验证参数值    /// </summary>    public object ParameterValue { get; set; }    /// <summary>    /// 验证结果    /// </summary>    public bool AuthorizeResult { get; private set; }    /// <summary>    /// 验证前获取moduleId    /// </summary>    public override void OnAuthorization(AuthorizationContext filterContext)    {        if (!IsSetModuleId)        {            var modules = filterContext.Controller.GetModules();            //一个模块的的时候,只第一次进入时获取他的模块id,缓存以后不作处理            if (modules.Count == 1 && ModuleId == null)             {                if (!string.IsNullOrWhiteSpace(modules[0].ParameterName))                {                    if (modules[0].CheckParameter(filterContext.HttpContext.Request))                        ModuleId = modules[0].ModuleId;                }                else                    ModuleId = modules[0].ModuleId;            }            //多个模块的时候,每次验证强制更新及moduleid            else if (modules.Count > 1)            {                foreach (var m in modules)                {                    if (m.CheckParameter(filterContext.HttpContext.Request))                    {                        ModuleId = m.ModuleId;                        break;                    }                }            }        }        base.OnAuthorization(filterContext);    }    /// <summary>    /// 核心验证    /// </summary>    protected override bool AuthorizeCore(HttpContextBase httpContext)    {        //如果未登陆,则跳转到登陆页        if (!httpContext.User.Identity.IsAuthenticated)            httpContext.Response.Redirect(FormsAuthentication.LoginUrl);        AuthorizeResult = true;        if (PermissionFlag != null)        {            if (PermissionFlag.Value == Permission.Administrator)                return AdminSiteService.CheckAdministrator();            //未设置模块id,则抛出异常            if (ModuleId == null)                throw new Exception(string.Format("未设置模块id的Control不能进行权限验证!"));            //处理二选一            if (PermissionFlag1 != null)            {                if (string.IsNullOrWhiteSpace(ParameterName))                    throw new Exception(string.Format("请为二选一验证指定相应的参数名!"));                //如果参数值等于给定值,则验证前者,否则验证后者                if (CheckParameter(httpContext.Request))                    AuthorizeResult = AdminSiteService.CheckPermission(ModuleId.Value, (int)PermissionFlag.Value);                else                    AuthorizeResult = AdminSiteService.CheckPermission(ModuleId.Value, (int)PermissionFlag1.Value);            }            else //一般验证处理            {                //如果参数名不为空,则先验证参数值是否匹配                if (!string.IsNullOrWhiteSpace(ParameterName))                    AuthorizeResult = CheckParameter(httpContext.Request);                if (AuthorizeResult)                    AuthorizeResult = AdminSiteService.CheckPermission(ModuleId.Value, (int)PermissionFlag.Value);            }        }        return AuthorizeResult;    }    /// <summary>    /// 错误处理    /// </summary>    protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)    {        filterContext.Result = new RedirectResult("~/Main/Error?code=100");    }    /// <summary>    /// 验证参数值是否有正确    /// </summary>    private bool CheckParameter(HttpRequestBase request)    {        var val = request[ParameterName];        bool b = false;        if (val == null && ParameterValue == null)            b = true;        else if (val != null && ParameterValue != null && val == ParameterValue.ToString())            b = true;        return b;    }}

注意AuthorizeAttribute缓存问题。第一访问时会缓存该Action的身份认证类,所以多模块验证时需要重新获取moduleId22gHTML5中文学习网 - HTML5先行者学习网

如果当前AuthorizeAttribute没有指定moduleid,则每次访问强制更新其moduleId22gHTML5中文学习网 - HTML5先行者学习网

补充一下获取控制器模块的扩展方法:22gHTML5中文学习网 - HTML5先行者学习网

/// <summary>    /// 获取控制器相关模块    /// </summary>    public static List<ModuleAttribute> GetModules(this ControllerBase controller, bool useCache = true)    {        if (controller == null)            return null;        string cacheKey = string.Format("{0}_Modules", controller.GetType().Name);        if (useCache)        {            if (CacheProvider.Cache.Contains<List<ModuleAttribute>>(cacheKey))                return CacheProvider.Cache.Get<List<ModuleAttribute>>(cacheKey);        }        var moduleInfos = controller.GetType().GetCustomAttributes(typeof(ModuleAttribute), false);        List<ModuleAttribute> modules = new List<ModuleAttribute>();        if (moduleInfos.Length <= 0)            return modules;        foreach (var m in moduleInfos)        {            modules.Add((ModuleAttribute)m);        }        if (useCache)            //缓存控制器模块信息            CacheProvider.Cache.Add<List<ModuleAttribute>>(cacheKey, modules, 20);        return modules;    }

验证方法主要是帮我们区分出是验证哪一个模块的哪一个权限,最后把模块id和权限标识传入我们的逻辑层进行验证,我们可以在登陆的时候缓存用户的模块权限。22gHTML5中文学习网 - HTML5先行者学习网

验证大致代码:22gHTML5中文学习网 - HTML5先行者学习网

/// <summary>        /// 判断当前登陆用户对操作是否有权限        /// </summary>        public static bool CheckPermission(int ModuleId, int permissionFlag)        {            //FormsAuthentication.GetAuthCookie()            var user = HttpContext.Current.User;            //未登陆的用户            if (!user.Identity.IsAuthenticated)                return false;            AdminInfo info = GetLoginAdminInfo();            //超级管理员有所有权限            if (info.RoleId == Constant.AdministratorRoleId)                return true;            if (!info.ModulePermissions.Exists(t => t.AdminId == info.AdminId &&                                                    t.ModuleId == ModuleId &&                                                    t.PermissionFlag == permissionFlag))                return false;            return true;        }

最后,我们就可以在我们的系统中使用了:22gHTML5中文学习网 - HTML5先行者学习网

using FL.Entitys;using FL.Site.Service;using FL.Site.SysManager.Common;using System;using System.Collections.Generic;using System.Linq;using System.Web;using System.Web.Mvc;using FL.Site.ViewModel;using FL.Site.SysManager.JUI;namespace FL.Site.SysManager.Controllers{    [Module(ModuleId = 7)]    public class AdminController : BaseController<AdminSiteService>    {        /// <summary>        /// 分页列表        /// </summary>        [SysAuthorize(Permission.List)]        public ActionResult List(PagerPostItem postPager)        {            var pager = new PagerItem(postPager, TargetType.NavTab);            int recordCount;            var list = Service.GetPageList(pager.currentPage, pager.numPerPage, out recordCount);            pager.totalCount = recordCount;            var roles = new RoleSiteService().GetRoles();            ViewBag.Roles = roles;            return View(list, pager);        }        /// <summary>        /// 编辑输入        /// </summary>        [SysAuthorize(Permission.Add, Permission.Update, "id")]        public ActionResult Edit(int? id)        {            var entity = new AdminSaveModel();            if (id != null)                entity = Service.GetById(id.Value);            var roles = new RoleSiteService().GetRoles();            ViewBag.Roles = new SelectList(roles, "RoleId", "RoleName", entity.RoleId);            return View(entity);        }        /// <summary>        /// 保存数据        /// </summary>        [HttpPost]        [SysAuthorize(Permission.Add, Permission.Update, "AdminId", 0)]        public ActionResult Edit(AdminSaveModel entity)        {            entity.LastUpdateTime = DateTime.Now;            entity.LastUpdateAdmin = UserInfo.LoginName;            if (ModelState.IsValid)                return Json(Service.Save(entity));            else                return Json(AjaxResult.NewModelCheckErrorResult(ModelState));        }        /// <summary>        /// 删除指定id的数据        /// </summary>        [SysAuthorize(Permission.Delete)]        public ActionResult Delete(int id,int roleId)        {            return Json(Service.Delete(id, roleId), false);        }        /// <summary>        /// 修改密码        /// </summary>        [SysAuthorize(Permission.Update)]        public ActionResult EditPwd(int id)        {            ViewBag.Id = id;            return View();        }        [HttpPost]        [SysAuthorize(Permission.Update)]        public ActionResult EditPwd(string Pwd, string ConfirmPwd, int id)        {            return Json(Service.UpdatePassword(Pwd, ConfirmPwd, id));        }        /// <summary>        /// 获取用户登陆日志        /// </summary>        [SysAuthorize(22, Permission.List)]        public ActionResult LoginLog(PagerPostItem postPager)        {            var pager = new PagerItem(postPager, TargetType.NavTab);            int recordCount;            var list = Service.GetLoginLogPageList(pager.currentPage, pager.numPerPage, out recordCount);            pager.totalCount = recordCount;            return View(list, pager);        }    }}

很久没写文章,有点小乱,也没提供代码及数据库相关的东西,也算是分享一种相法吧。程序一个人写久了很寂寞22gHTML5中文学习网 - HTML5先行者学习网

  数据库大致结构:模块表,角色表,用户表,模块权限表,角色模块权限表,用户角色表,  另外写一个视图获取用户的模块权限,在登陆的时候缓存,就可以使用上面的方式验证了。22gHTML5中文学习网 - HTML5先行者学习网

总结:在基于模块的权限验证系统中,只需要为程序提供模块,登陆用户及要验证的权限,就可以非常方便的验证用户权限。上面的一系列代码都是为了取得我们想要的模块id和权限22gHTML5中文学习网 - HTML5先行者学习网

缺点:模块id和权限代码不能随便更改,当然,可以用一个常量类来保存我们的模块和权限,但是总的上来说,还可以将就使用的。22gHTML5中文学习网 - HTML5先行者学习网

22gHTML5中文学习网 - HTML5先行者学习网
22gHTML5中文学习网 - HTML5先行者学习网
(责任编辑:)
推荐书籍
推荐资讯
关于HTML5先行者 - 联系我们 - 广告服务 - 友情链接 - 网站地图 - 版权声明 - 人才招聘 - 帮助