本章主要讲解在MVC中灵活控制Action的访问权限;

本章所使用的示例表也是上一张所使用的TbUser、TbRole、TbUserRole;

最终的效果是针对任意一个Action或Controller,都可以根据配置的角色来控制访问权限;

完成此核心功能后,可以再往两方面扩展常用功能:

1. 可以根据 组织/用户/角色 的并集来控制权限

2. 以此核心功能为基础,实现菜单的动态配置

PS:扩展功能本章暂时不讲

文章提纲

  • 概述
  • 理论基础
  • 详细步骤
  • 总结

概述

一、MVC Form认证身份基础

通常用法举例:

1. web.config配置,开启form认证

2. 需要认证的 Control或Action 上添加过滤,例如限制只有用户"zhangsan"或者角色"管理员"可以访问

    

另外还有一种常用形式表示:只要有用户登录就可以访问

就是直接在Action或整个Controller上[Authorize]属性过滤

二、为什么需要自定义MVC权限过滤器

上述解决方式中很明显会发现有两个缺点:

1. 修改权限时需在Action, Controller上修改后需重新编译,不灵活。

2.过滤器中的Role是内置对象,如果不使用ASP.NET自身的集成权限方案,就无法按照角色来过滤。

解决这两个问题,只需要扩展类AuthorizeAttribute即可。

理论基础

为了能使用自定义的角色控制权限,我们需要扩展或绕过 ASP.NET 的Membership和Role provider 框架。

1.扩展:实现自定义的 Membership/Role provider

2.绕过:直接不使用

我们选择绕过的方式,这样的话更加灵活。

(因为如果你的角色结构和系统不一致,用扩展的方式弄起来比较麻烦)

我们使用form认证的三个核心API, 只用这几个API既可以减少工作量,又可以和Membership/Role provider保持独立。

1. FormsAuthentication.SetAuthCookie

用户登录后,指定用户名

2. Request.IsAuthenticated

登录后返回true

3. HttpContext.Current.User.Identity.Name

返回登录的用户名

权限过滤的完整过程:

1. Authetication ( 登录 )

登录成功后,调用 FormsAuthentication.SetAuthCookie 设置一个用户名。

2. Authorization(授权)

新建自定义的授权属性类:CustomAuthorizeAttribute(继承于AuthorizeAtrribute),扩展权限过滤器

3. 类似于默认Authorize attribute的使用方法,附加自定义的authorize attribute到controller或action上去,实现权限过滤

详细步骤

一、启用form认证,完成登录/退出 基本功能

1. 启用 form 认证

配置web.config,启用form认证

2. 完成登录/退出 基本功能

新建Controller: AccountController.cs

    public class AccountController : Controller
{
private MyDbContext db = new MyDbContext();
// GET: Account
public ActionResult Index()
{
return View();
} public ActionResult Login()
{
ViewBag.LoginState = "登录前...";
TempData["returnUrl"] = Request["ReturnUrl"];
//如果当前有登录用户,就需要跳转到权限不足提示页面
if (!string.IsNullOrEmpty(User.Identity.Name))
{
return View("NoPermissions");
}
else
{
return View();
}
}
[HttpPost]
public ActionResult Login(TbUser user)
{
string url = Convert.ToString(TempData["returnUrl"]);
var userinfo = db.TbUsers.FirstOrDefault(u => u.Email == user.Email && u.Password == user.Password);
if (userinfo != null)
{
FormsAuthentication.SetAuthCookie(userinfo.UserName, false);
if (!string.IsNullOrEmpty(url))
{
ViewBag.LoginState = userinfo.UserName + "登录后...";
return Redirect(url);
}
else
{
return Redirect("~/");
} }
else
{
ViewBag.LoginState = user.Email + "用户不存在...";
}
return View();
} public ActionResult Logout()
{
FormsAuthentication.SignOut();
return Redirect(Request.UrlReferrer.ToString());
}
/// <summary>
/// 权限不足页面
/// </summary>
/// <returns></returns>
public ActionResult NoPermissions()
{
return View();
} }

登录功能:

登出功能:

这里对应的视图文件就不展示了

二、准备好权限配置文件

1. 用到的基础数据:用户,角色及用户/角色 关系

2. 角色与Action对应的权限关系

这里我们先用一个xml代替,理解这个后就可以扩展到DB中。

新建文件夹Config,新建ActionRoles文件,配置Action/Role的对应关系

PS:

Action未配置情况下,默认有访问权限;

Action 配置角色为空,有访问权限。

三、扩展 AuthorizeAttribute

1. 新建类CustomAuthorizeAttribute,继承与AuthorizeAttribute

override两个方法:

在请求授权时调用:

提供一个入口点用于自定义授权检查,通过为true

CustomAuthorizeAttribute.cs(两个方法的具体实现):

    public class CustomAuthorizeAttribute : AuthorizeAttribute
{
private MyDbContext db = new MyDbContext(); /// <summary>
/// 对应Action允许的角色
/// </summary>
private string[] AuthRoles { get; set; }
/// <summary>
/// 在请求授权时调用
/// </summary>
/// <param name="httpContext"></param>
/// <returns></returns>
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
if (httpContext == null)
{
throw new ArgumentNullException("HttpContext");
}
if (AuthRoles == null || AuthRoles.Length == )
{
return false;
}
#region 确定当前用户角色是否属于指定的角色
//获取当前用户所在角色
string sql = "select RoleName from TbRole where Id in(select roleId "
+ "from TbUserRole where userid = "
+ "(select id from TbUser where UserName=@UserName))";
string currentUser = httpContext.User.Identity.Name;
SqlParameter[] paras = new SqlParameter[] {
new SqlParameter("@UserName",currentUser)
};
var userRoles = db.Database.SqlQuery<string>(sql, paras).ToList();
//验证是否属于对应角色
for (int i = ; i < AuthRoles.Length; i++)
{
if (userRoles.Contains(AuthRoles[i]))
{
return true;
}
}
#endregion
return false;
}
/// <summary>
/// 提供一个入口点用于自定义授权检查,通过为true
/// </summary>
/// <param name="filterContext"></param>
public override void OnAuthorization(AuthorizationContext filterContext)
{
string controllerName = filterContext.ActionDescriptor.ControllerDescriptor.ControllerName;
string actionName = filterContext.ActionDescriptor.ActionName;
//获取config文件配置的action允许的角色,以后可以转到数据库中
string roles = GetActionRoles(actionName, controllerName);
if (!string.IsNullOrWhiteSpace(roles))
{
this.AuthRoles = roles.Split(new string[] { "," }, StringSplitOptions.RemoveEmptyEntries);
}
else {
this.AuthRoles = new string[] { };
}
base.OnAuthorization(filterContext);
}
/// <summary>
/// 根据当前Controller和Action名称获取对应节点内容
/// </summary>
/// <param name="action">Action名称</param>
/// <param name="controller">Controller名称</param>
/// <returns></returns>
private static string GetActionRoles(string action, string controller)
{
XElement rootElement = XElement.Load(HttpContext.Current.Server.MapPath("~/Configs/") + "ActionRoles.xml");
XElement controllerElement = FindElementByAttribute(rootElement, "Controller", controller);
if (controllerElement != null)
{
XElement actionElement = FindElementByAttribute(controllerElement, "Action", action);
if (actionElement != null)
{
return actionElement.Value;
}
}
return "";
} private static XElement FindElementByAttribute(XElement xelement, string tagName, string attribute)
{
XElement nowXelement = xelement.Elements(tagName).FirstOrDefault(e => e.Attribute("name").Value.Equals(attribute, StringComparison.OrdinalIgnoreCase));
return nowXelement;
}
}

总结

在此,权限控制的整个过程就差不多了,我们来测试一下。

新建HomeController, 新建一些Action做测试(Index, About,Install,Other)

回顾一下基础数据。

HomeController.cs

namespace TestMVC.Controllers
{
[CustomAuthorizeAttribute]
public class HomeController : Controller
{
// GET: Home
public ActionResult Index()
{
return View();
} public ActionResult About()
{
return View();
}
public ActionResult Install()
{
return View();
}
public ActionResult Other()
{
return View();
}
}
}

对应视图:

补充说明:

如下图,可以设置为全局。

这样就不需要单个设置,对所有Action应用自定义过滤条件。

源码下载

MVC5+EF6 --自定义控制Action访问权限的更多相关文章

  1. SQLServer控制用户访问权限表

    连接地址:http://www.cnblogs.com/yxyht/archive/2013/03/22/2975880.html 一.需求 在管理数据库过程中,我们经常需要控制某个用户访问数据库的权 ...

  2. 使用Spring安全表达式控制系统功能访问权限

    一.SPEL表达式权限控制 从spring security 3.0开始已经可以使用spring Expression表达式来控制授权,允许在表达式中使用复杂的布尔逻辑来控制访问的权限.Spring ...

  3. geoserver控制服务访问权限-类似百度地图的key

    目录 缘起 可行性分析 如何实现key验证访问 如何控制key能访问哪些地图服务? 如何实现服务器ip白名单 流程梳理 申请key 访问地图 实施步骤 拦截器设置 配置key验证规则 配置服务拦截规则 ...

  4. Chapter6_访问权限控制_访问权限修饰词

    Java中有四种访问权限,public,private,protected和包访问权限,它们是置于类中每一个成员之前的定义,无论是一个域还是一个方法,下面一一介绍. 一.包访问权限 如果不提供任何访问 ...

  5. ASP.NET MVC5+EF6+EasyUI 后台管理系统--系统权限全套完整图

    根据角色或用户或模块查询权限.

  6. ASP.NET MVC5+EF6+EasyUI 后台管理系统--系统权限及操作指引

    系列目录 1.权限包括菜单权限,按钮权限,数据权限 2.角色组和用户之间是多对多的关系,即多个用户可以拥有多个角色组,权限是拥有角色组的并集 1.菜单界面,菜单都是动态数据由模块管理进行设置 2.权限 ...

  7. .NET WebAPI 用ActionFilterAttribute实现token令牌验证与对Action的权限控制

    项目背景是一个社区类的APP(求轻吐...),博主主要负责后台业务及接口.以前没玩过webAPI,但是领导要求必须用这个(具体原因鬼知道),只好硬着头皮上了. 最近刚做完权限这一块,分享出来给大家.欢 ...

  8. WebAPI 用ActionFilterAttribute实现token令牌验证与对Action的权限控制

    .NET WebAPI 用ActionFilterAttribute实现token令牌验证与对Action的权限控制 项目背景是一个社区类的APP(求轻吐...),博主主要负责后台业务及接口.以前没玩 ...

  9. 用Lua控制Nginx静态文件的url访问权限

    需求背景:比如我们有一个存储文件的web服务器,一般通过url可直接访问到:http://127.0.0.1/uploads/test.rar,如果我们需要限制别人的访问,可以通过添加lua脚本来控制 ...

随机推荐

  1. (后端)SQL SERVER 字符串按数字排序

    应用于B1-1,B1-2,B10-1,B11-1 sqlserver肯定不能按照字符串进行排序,需要进行处理一番: select CONVERT(varchar, LEFT(code,1)),conv ...

  2. Redis数据类型及命令

    Redis简介 Redis是一个完全开源免费的, 是一个高性能的key-value数据库. Redis 与其他 key - value 缓存产品有以下三个特点: Redis支持数据的持久化,可以将内存 ...

  3. 【Apache运维基础(6)】Apache的日志管理与分析

    简述 Apache 访问日志在实际工作中非常有用,比较典型的例子是进行网站流量统计,查看用户访问时间.地理位置分布.页面点击率等.Apache 的访问日志具有如下4个方面的作用: 记录访问服务器的远程 ...

  4. 服务器 'xxxx' 已被定义为分发服务器。若要将该服务器重新配置为分发服务器,必须首先卸载现有的分发服务

    使用AWS DMS(Database Migration Service)将SQL Server数据库同步到AWS的Data Lake上,需要在本地源数据库上配置复制,在配置分发向导最后一步时,遇到下 ...

  5. SQL SERVER 查询表的行数

    SELECT OBJECT_NAME(ii.id) TableName ,rows FROM sysindexes ii INNER JOIN sysobjects oo ON ( oo.id = i ...

  6. python 进程池的简单使用方法

    回到python,用一下python的进程池. 记得之前面试的时候,面试官问:你知道进程池的默认参数吗? 我没有回答上来,后来才知道,是有默认参数的.下面就看看它的默认参数 1. 不加参数 from ...

  7. TCP/IP协议族(笔记)

    1.HTTP HTTPS DCHP ICMP  SMTP IMAP MIME POP PPTP 协议族 tcp/ip 是基于tcp和ip这两个最初的协议之上的不同的通信协议的大集合 TCP/IP不是一 ...

  8. 第七章 LED将为我闪烁:控制发光二级管

    LED驱动开发实验 如图所示,LED1-LED2 分别与GPC0_3.GPC0_4 相连,通过GPC0_3.GPC0_4 引脚的高低电平来控制三极管的导通性,从而控制LED 的亮灭. 根据三极管的特性 ...

  9. Linux中“!"的神奇用法

    前言 实际上,不起眼的“!”在linux中有着很多让你惊叹的妙用.本文就来细数那些“!”的神奇用法. 执行上一条命令 例如,在执行完上面一条命令后,可以使用下面的方式再次执行上一条命令: $ wher ...

  10. Java学习笔记(三)——封装、继承、多态

    一.封装 概念: 将类的某些信息隐藏在类内部,不允许外部程序直接访问,而是通过该类提供的方法来实现对隐藏信息的操作和访问. 实现步骤: 修改属性的可见性——设为private. 创建getter/se ...