zoukankan      html  css  js  c++  java
  • MVC中权限的知识点及具体实现代码

    一:知识点部分

    权限是做网页经常要涉及到的一个知识点,在使用MVC做权限设计时需要先了解以下知识:

    MVC中Url的执行是按照Controller->Action->View页面,但是我们经常需要在函数执行所指定的Action之前或者action方法之后处理一些逻辑,为了处理这些逻辑,ASP.NET MVC允许你创建action过滤器Filter,我们都知道在Action上使用的每一个 [Attribute]大都是自定义的Filter。

    mvc提供四种类型的Filter接口:IActionFilter,IAuthorizationFilter,IExceptionFilter,IResultFilter, 这四种Filter足以满足我们所要实现的功能,它还提供了几个现

    成的可以使用的Filter:OutputCacheAttribute、 HandleErrorAttribute、AuthorizeAttribute。(AuthorizeAttribute 和 HandleErrorAttribute继承自FilterAttribute 类)

    其中:

    IActionFilter提供的两种方法: OnActionExecuting 在调用操作方法前调用OnActionExecuted 在调用操作方法后调用。

    IResultFilter提供的两种方法:OnResultExecuting 在执行由操作方法返回的操作结果前调用。OnResultExecuted 在执行由操作方法返回的操作结果后调用。

    IAuthorizationFilter是一个用于身份验证的Filter。只提供了一个void OnAuthorization(AuthorizationContext filterContext)方法。

    IExceptionFilter会在出现异常的时候调用,也是只提供一个void OnException(ExceptionContext filterContext)的方法;

    而4个接口的方法执行顺序如下:IAuthorizationFilter -> IActionFilter - >IResultFilter ->IExceptionFilter

    【 ActionExecutedContext类包含一个 Canceled的属性,允许你取消当前的 Action】

    现在我们来看一下用得最多的一个类ActionFilterAttribute:

    他的继承层次结构为

    System.Object
      System.Attribute
        System.Web.Mvc.FilterAttribute
          System.Web.Mvc.ActionFilterAttribute
            System.Web.Mvc.AsyncTimeoutAttribute
            System.Web.Mvc.OutputCacheAttribute

    public abstract class ActionFilterAttribute : FilterAttribute, IActionFilter, IResultFilter{
    }
    他继承了 FilterAttribute, IActionFilter, IResultFilter三个类,通常我们在Action逻辑之前需要处理一些功能,比如权限等,因此会自定义一个Filter,它继承于
    ActionFilterAttribute ,然后再
    在ActionFilterAttribute 中重载由接口 IActionFilter, IResultFilter继承下来的函数
    void
    OnActionExecuting(ActionExecutingContext filterContext)

    void OnActionExecuted(ActionExecutedContext filterContext)
    void OnResultExecuting(ResultExecutingContext filterContext)
    void OnResultExecuted(ResultExecutedContext filterContext)

    其中ActionFilterAttribute有两个属性,一个是继承FilterAttribute,另一个继承Attribute

    Order 获取或者设置执行操作筛选器的顺序。 (继承自 FilterAttribute。)

    TypeId 当在派生类中实现时,获取该 Attribute 的唯一标识符。 (继承自 Attribute。)

    例如如下代码段:

    [orderFilter(RoleId="2",Order=2)]
    [UserFilter(UserId
    ="3",Order=1)]
    public ActionResult test() {
    return View();
    }

    程序在执行的顺序为:UserFilter->orderFilter->test

    二:实例部分

    了解上面的一些知识后,我们来看一下我设计的权限实例:
    如果不知道用户,角色,组,权限之前的一些关系,建议你先看我上一篇“权限的基础知识”,这篇文章是我转过来的,觉得还不错,因为之前自己做完项目后没
    分的很清楚,现在
    看完那篇文章,对号入座,才清楚原来我也是按照用户,角色,组,权限等这些关系来进行着 ^_^(如果下面对号入座的不对,请大家指正)
    假设现在有4种功能权限: 添加功能、删除功能、发布功能、修改功能等。按照二进制01格式来设计,0表示没有该功能权限,1表示有该权限,
    也就是说,按照顺序
              添加 删除 发布 修改
              1 1 1 1   如果只有修改功能 就是0001,
                          如果有添加及删除功能 就是1100,

    将二进制转换为int数 添加功能:(1000=int数 8) 删除功能:(0100=int数 4) 发布功能:(0010=int数 2) 修改功能:(0001 =int数 1)
                这我可以理解为 -----权限
    而每个用户拥有的功能(权限)是不一样的 ,可以有多种组合, 比如1001(添加及修改权限) 0011(发布及修改权限) 1111(全部权限)
                这我可以理解为-------组
    而对不同用户我将他们的权限组合功能变为int 数存于user表的Permission(int)字段中,这样的话:(添加及修改权限1001=int数 9)
    (发布及修改权限0011=int 数 3) (全部权限1111=int数 15)

                这我可以理解为--------角色
    至于用户就是我们自己数据库里面的username了.

    设置用户权限:只需要将所拥有功能权限的int数相加存入数据库就可;
    查看用户权限:则需要先将Permission的int值解析为二进制数,然后再看为1 的位数的int数值与对应的功能值就可。
    实现: 当用户登录的时候,先查看他的Permission的int值(就是角色),将角色解析为相应的组,将每组的权限int值载入用户主体的Roles,他是一个数组形式。
    (因为有一种或多种功能权限)

    然后在每个需要进行权限过滤的Action上加上自定义的Filter:即在重载的OnActionExecuting方法内判断是否当前用户的Roles里面存在该功能权限,如果存在,
    则进入页面,否则跳到无权限页面。


    下面就是代码了,继承ActionFilterAttribute类,并且重载OnActionExecuting方法:

    publicclass RoleFilter : ActionFilterAttribute {
    publicstring checkRole { get; set; } //应传入的功能权限值
    publicoverridevoid OnActionExecuting(ActionExecutingContext filterContext) {
    if(!string.IsNullOrEmpty(checkRole)) {
    if(!filterContext.HttpContext.User.Identity.IsAuthenticated) { //判断用户是否已经登录,没登录跳转到登录页面,
    string okurl = filterContext.HttpContext.Request.RawUrl;
    string redirectUrl =string.Format("?ReturnUrl={0}", okurl);
    string loginUrl = FormsAuthentication.LoginUrl + redirectUrl;
    filterContext.Result
    =new RedirectResult(loginUrl);
    }
    else { //已登录用户
    bool isAuthorize = filterContext.HttpContext.User.IsInRole(checkRole);
    if(!isAuthorize) //判断用户是否拥有checkRole权限,没有的话跳转到权限错误页。
    filterContext.Result =new RedirectToRouteResult("Default", new RouteValueDictionary(new { Controller ="Account", Action ="AuthorizeError" }));
    }
    }
    else {
    thrownew InvalidOperationException("该用户没有指定角色,请联系管理员给予角色。");
    }
    }
    }

    在程序刚启动的时候如要读取用户角色的权限。才好做上面的比较:
    public MvcApplication() {
    AuthorizeRequest
    +=new EventHandler(MvcApplication_AuthorizeRequest);
    }

    void MvcApplication_AuthorizeRequest(object sender, EventArgs e) {
    //获取当前用户的角色
    if(HttpContext.Current.User.Identity.IsAuthenticated) {
              //下面这个方法是将role(int)转换为二进制 然后算个每个权限的int值 数组
    var roles
    = CMSPermissionController.Instance.PermissionIdList(HttpContext.Current.User.Identity.Name.Trim()).ToArray<string>();
    HttpContext.Current.User
    =new System.Security.Principal.GenericPrincipal(HttpContext.Current.User.Identity, roles);
    }
    }
    调用的过程为:

    //根据需要你也可以对整个Controller加【attribute】
    [RoleFilter(checkRole ="2")]
    publicclass GroupController : Controller {
    public ActionResult Index() {
    return View();
    }

    public ActionResult Create() {
    return View();
    }
    }

    //也可以对某个特定的Action添加
    [RoleFilter(checkRole ="4")]
    publicstring Delete(string RelaPath) {
    //to do ...
    }
    上面的代码基本上就可以实现了,在调试的过程中,曾经有个同事问,如果我要在Delete上也要检查checkRole="8"的时候你怎么办,我当时有点懵。。。没想
    太多,就觉得那到底是先checkRole是4
    还是先checkRole是“8”呢,现在看来,不存在那样状况, 因为我定义的4,8等数字, 本身就是定死的权限,比如
    添加 删除 发布 修改对应的权限数字是8,4,2,1;所以如果我们要对Delete本来是4的权限,
    来检查添加的权限8,业务逻辑上本身也是不存在的! O(∩_∩)O

    还看到一篇关于权限的文章:是用当前的url来判断的,很值得学习,供以后研究:
    http://www.cnblogs.com/legendxian/archive/2010/01/25/1655551.html













  • 相关阅读:
    C#学习记录二:高级数据存储方式
    SharePoint 2010 匿名用户调用Client Object Model访问列表项
    Android 在闹钟开机时,如何解决开机动画没有播完就进入Launcher M
    Getting in Line UVA 216
    Android 如何关闭Navigation Bar M
    google protocol buffer 简介 版本 安装 使用 实例
    Android [VP]视频播放器播放本地视频时收到短信/彩信,需要界面提示 M
    Maven教程初级篇02:pom.xml配置初步
    当Ruby的model名字出错时,在现实view时显示错误的提示
    VS Code 安装 C++ 调试环境
  • 原文地址:https://www.cnblogs.com/Joans/p/2110775.html
Copyright © 2011-2022 走看看