在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. hdu1875 畅通工程再续 最小生成树并查集解决---kruskal

    http://acm.hdu.edu.cn/showproblem.php?pid=1875 New~ 欢迎“热爱编程”的高考少年——报考杭州电子科技大学计算机学院关于2015年杭电ACM暑期集训队的 ...

  2. 什么是automatic variable?

    看代码符号$?搞不清楚是什么?   看代码. $share = Get-WmiObject -Class Win32_Share -ComputerName $Server.name -Credent ...

  3. Android开发的技术层次

    任何一种移动开发生态系统其技术人员都是呈现金字塔式分布的.我借此也说说Developer和Programmer的区别: Programmer是真正意义上的程序员,写程序的.灵魂级 Developer是 ...

  4. 斐波那契数列(Fibonacci)递归和非递归实现

    序列前9项为:0, 1, 1, 2, 3, 5, 8, 13, 21 要注意非递归的话就是那一个变量帮助存储当前下一项的值,然后依次挪动两个指针往下即可 注意如果n太大 会溢出             ...

  5. 画之国 Le tableau (2011)

    在佛斯特的肚子里,靠近幽门的地方,两只阿米巴原虫快乐地生活着.他们的日子过得很舒服,从来没饿过肚子,而且根本用不着干活:因为他们就是所谓的寄生虫.这两个好朋友相处得很愉快,但时不时也会争论不休,因为他 ...

  6. iPhone开发视频教程 Objective-C部分 (51课时)

    第一.二章  OC基础语法 iPhone开发教程 第一章 OC基础语法  iPhone开发概述-必看(1.1)http://www.apkbus.com/android-102215-1-1.html ...

  7. JavaScript学习汇总

    对于JavaScript,还是无法割舍,有心无力,时间总是匆匆,暂且都放在这里吧 javascript中this的使用 写的很不错的一偏文章,简单看了下,mark了吧 原文:http://davids ...

  8. Zone.js 简介 & 抛砖引玉

    Zone.js是angular团队参照NodeJS的Domain,Dart的Zone,为angular 2开发的核心组件. 一开始,我对Zone.js是拒绝的.我们知道类似的 Domain 模块,主要 ...

  9. WPF WebBrowser屏蔽弹出alert ,confirm ,prompt ,showModalDialog() ,window.open()

    WPF WebBrowser屏蔽弹出alert ,confirm ,prompt ,showModalDialog() ,window.open()添加Microsoft.mshtml.dll,然后写 ...

  10. Java Inner Classes

    When thinking about inner classes in java, the first thing that comes to my mind is that, WHY do we ...