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

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

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

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

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

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

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

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

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

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

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

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

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

对于第四种情况,我们可以为模块添加不同的参数module对应关系

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

想法定好以后,我们就可以去实现了。

首先,我们定义一个module的特性:

/// <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;
}
}

实现了模块特性以后,就是比较重要的验证特性了:

/// <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 == && ModuleId == null)
{
if (!string.IsNullOrWhiteSpace(modules[].ParameterName))
{
if (modules[].CheckParameter(filterContext.HttpContext.Request))
ModuleId = modules[].ModuleId;
}
else
ModuleId = modules[].ModuleId;
}
//多个模块的时候,每次验证强制更新及moduleid
else if (modules.Count > )
{
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的身份认证类,所以多模块验证时需要重新获取moduleId

如果当前AuthorizeAttribute没有指定moduleid,则每次访问强制更新其moduleId

补充一下获取控制器模块的扩展方法:

/// <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 <= )
return modules;
foreach (var m in moduleInfos)
{
modules.Add((ModuleAttribute)m);
}
if (useCache)
//缓存控制器模块信息
CacheProvider.Cache.Add<List<ModuleAttribute>>(cacheKey, modules, );
return modules;
}

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

验证大致代码:

        /// <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;
}

最后,我们就可以在我们的系统中使用了:

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 = )]
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", )]
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(, 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);
}
}
}

很久没写文章,有点小乱,也没提供代码及数据库相关的东西,也算是分享一种相法吧。程序一个人写久了很寂寞

数据库大致结构:模块表,角色表,用户表,模块权限表,角色模块权限表,用户角色表,  另外写一个视图获取用户的模块权限,在登陆的时候缓存,就可以使用上面的方式验证了。

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

缺点:模块id和权限代码不能随便更改,当然,可以用一个常量类来保存我们的模块和权限,但是总的上来说,还可以将就使用的。

Asp.net Mvc4 基于Authorize实现的模块权限验证方式的更多相关文章

  1. Asp.net Mvc4 基于Authorize实现的模块访问权限

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

  2. asp.net web form中 用attribute实现权限验证方式

    以前项目的代码比较陈旧,今天抽空优化了一下.作为记录. 以前每次请求一个方法都要验证是否登录 if xxx等  现在通过global文件中的改进 反射这个方法的属性是否需要权限 要的话先验证权限.以下 ...

  3. asp.net mvc4 过滤器的简单应用:登录验证

    直接上代码,不要说话. ASP.NET MVC4过滤器的简单应用:验证登录 [AcceptVerbs(HttpVerbs.Post)] public ActionResult login(FormCo ...

  4. 【翻译转载】【官方教程】Asp.Net MVC4入门指南(6):验证编辑方法和编辑视图

    本节中,您将开始修改为电影控制器所新加的操作方法和视图.然后,您将添加一个自定义的搜索页. 在浏览器地址栏里追加/Movies, 浏览到Movies页面.并进入编辑(Edit)页面. Edit(编辑) ...

  5. Asp.Net MVC4入门指南(6):验证编辑方法和编辑视图

    在本节中,您将开始修改为电影控制器所新加的操作方法和视图.然后,您将添加一个自定义的搜索页. 在浏览器地址栏里追加/Movies, 浏览到Movies页面.并进入编辑(Edit)页面. Edit(编辑 ...

  6. 主攻ASP.NET MVC4.0之重生:发邮箱激活验证

    导入Interop.jmail组件 using jmail;using System.Net.Mail; 点击下载源代码 Controller相关代码 public class SendEmailCo ...

  7. mongoDB在windows下基于配置文件的安装和权限配置方式

    下载mongoDB  http://www.mongodb.org/downloads 根据操作系统,选择需要下载的安装包 添加mongodb 安装目录 将解压的文件夹中内容拷贝,存放在想要安装的文件 ...

  8. 基于 Annotation 的 Spring AOP 权限验证方法的实现

    1. 配置 applicationContext 在 Spring 中支持 AOP 的配置非常的简单,只需要在 Spring 配置文件 applicationContext.xml 中添加: < ...

  9. Asp.Net MVC4 + Oracle + EasyUI 学习 第一章

    Asp.Net MVC4 + Oracle + EasyUI  第一章 --操作数据和验证 本文链接:http://www.cnblogs.com/likeli/p/4234238.html 文章集合 ...

随机推荐

  1. Ubuntu 安装JDK步骤 ,提示没有那个文件或目录

    作为一个程序员,配置环境是最基本的功夫,然而我却捣鼓了一下午,包括安装Ubuntu,安装JDK和配置环境变量. 简单记录下自己的安装过程: 1  下载JDK tar包,使用tar -xzvf jdk* ...

  2. Enterprise Solution 2.2 开发帮助文档集合

    首先是一个PPT文档,从宏观层面展示Enterprise Soltion的几个功能特色. Enterprise Solution解决方案安装与配置 将源代码解决方案和演示程序在电脑中进行配置,作为了解 ...

  3. android: SQLite查询数据

    掌握了查询数据的方法之后,你也就将数据库的 CRUD 操 作全部学完了.不过千万不要因此而放松,因为查询数据也是在 CRUD 中最复杂的一种 操作. 我们都知道 SQL 的全称是 Structured ...

  4. Mac OS X 系统12个常用的文本编辑快捷键(移动、选中)

    经常和文字处理打交道?如果多多使用下面这 12 个快捷键,在移动.选择.复制等操作文字时效率会大大提升. 6 个移动光标的快捷键第一组快捷键可以用来在文本中快速移动光标: 跳到本行开头 – Comma ...

  5. LoadRunner在移动端性能测试的应用

    摘选自 <精通移动app测试实战:技术.工具和案例>新书上市 如果大家之前做过性能测试,我相信一定会应用过大名鼎鼎的性能测试工具-LoadRunner.目前LoadRunner的最新版本为 ...

  6. Swift入门篇-基本类型(3)

    一:元组 格式 变量或常量关键字 元组变量 = ( 变量,变量, …) 说明: : 元组变量还是一个变量,只不过表现方式和其他变量不一样 :()括号里面可以放入N个变量组成 例子: import Fo ...

  7. eclipse下开发winform的插件WindowBuilder

    可以开发swt,xwt等c/s应用 WindowBuilder插件可以在MarketPlace下载到,Help->Eclipse MarketPlace 可视化开发界面:

  8. Scala 深入浅出实战经典 第76讲:模式匹配下的赋值语句

    王家林亲授<DT大数据梦工厂>大数据实战视频 Scala 深入浅出实战经典(1-87讲)完整视频.PPT.代码下载: 百度云盘:http://pan.baidu.com/s/1c0noOt ...

  9. nginx 反向代理 与 Apache backend的配置联合配置

    nginx 反向代理 与 Apache backend的配置联合配置: 说明: nginx 将http映射到Apache上的特定子目录. 配置方法步骤: 1.  设置域名, 子域名映射到指定服务器ip ...

  10. 【黑金原创教程】【FPGA那些事儿-驱动篇I 】【实验一】流水灯模块

    实验一:流水灯模块 对于发展商而言,动土仪式无疑是最重要的任务.为此,流水灯实验作为低级建模II的动土仪式再适合不过了.废话少说,我们还是开始实验吧. 图1.1 实验一建模图. 如图1.1 所示,实验 ...