文档章节

通过建立自己的AuthorizeAttribute实现网站的权限管理

jamesvon
 jamesvon
发布于 2016/04/14 13:03
字数 2040
阅读 24
收藏 0
点赞 2
评论 0

当我们用.net MVC构建网站平台的时候,势必会对网站平台的安全性和用户的使用权限进行一个统一的构建,首先在.net MVC 架构中,系统已经将权限管理分为三个层面来进行管理,第一层面是 登录管理,也就是说在这个层面上完成用户口令的验证,即完成用户的登录,系统保存用户的登录记录。第二层面是授权,即赋予用户是否具备使用权限,是通过 AuthorizeAttribute 的特性来进行控制和管理的。第三个层面是是凭据缓存机制,系统建立System.Security.Claims.Claim来实现的,一旦登录成功系统就会在Cookies里面缓存给用户一个Claim,这样完成了用户登录信息的缓存。

那么如果对某一个模块具体进行权限控制呢?为了建立一个更加灵活的管理机制,我们采用了建立自己的 AuthorizeAttribute 来完成。首先我们来对需求进行一个简单的分析,如下图所示:一个功能模块我们可以通过指定用户,或指定权限来完成,也可能在使用时,通过角色和权限的控制来完成。

也就是说用户可以通过用户,也可以通过角色来进行控制,也可以在运行期通过角色和功能模块的指定来进行。

针对这个需求,我们建立了如下数据结构:

人员和角色是通过用户归属角色表进行关联的,而“功能权限控制”是功能直接和用户还是角色关联控制的。

为了实现这个功能设计,首先我们先在Models中建立四个基础信息类

namespace VonPortal.Web.Models
{
    /// <summary>人员基本信息 信息类</summary>
    public class UserInfo : IUser<int>
    {
        public int Id
        {
            get { return ID; }
        }
        #region "Public Properties"
        /// <summary>序号</summary>
        [Required]
        [Display(Name = "序号")]
        public int ID { get; set; }
        /// <summary>登录名</summary>
        [Required]
        [Display(Name = "登录名")]
        public string UserName { get; set; }
        /// <summary>姓氏</summary>
        [Display(Name = "姓氏")]
        public string FirstName { get; set; }
        /// <summary>名字</summary>
        [Display(Name = "名字")]
        public string LastName { get; set; }
        /// <summary>显示名称</summary>
        [Display(Name = "显示名称")]
        public string DisplayName { get; set; }
        /// <summary>称谓</summary>
        [Display(Name = "称谓")]
        public string Title { get; set; }
        /// <summary>简称</summary>
        [Required]
        [Display(Name = "简称")]
        public string ShortName { get; set; }
        /// <summary>电子邮箱</summary>
        [Required]
        [Display(Name = "电子邮箱")]
        public string EMail { get; set; }
        /// <summary>登录口令</summary>
        [Display(Name = "登录口令")]
        public string Password { get { return _Password; } set { _Password = UserCtrl.CryptPassword(value); } }
        internal string _Password = "";
        /// <summary>创建时间</summary>
        [Display(Name = "创建时间")]
        public DateTime CreateDate { get; set; }
        /// <summary>最后访问时间</summary>
        [Display(Name = "最后访问时间")]
        public DateTime LastAccess { get; set; }
        #endregion
    }
}
#region "角色信息信息类声明"
namespace VonPortal.Web.Models
{
    /// <summary>角色信息 信息类</summary>
    public class RoleInfo : IRole<int>
    {
        public int Id
        {
            get
            {
                return ID;
            }
        }

        public string Name
        {
            get
            {
                return RoleName;
            }

            set
            {
                RoleName = value;
            }
        }
        #region "Constructors"
        /// <summary>
        /// 构造函数
        /// </summary>
        public RoleInfo()
        {
        }
        /// <summary>
        /// 含初始化构造函数
        /// </summary>
        /// <param name="ID">序号</param>
        /// <param name="GroupName">组名称</param>
        /// <param name="RoleName">角色名称</param>
        /// <param name="SiteIdx">站点序号</param>
        /// <param name="ParentIdx">上级节点</param>
        /// <param name="InheritKind">继承关系</param>
        /// <param name="Description">角色说明</param>
        public RoleInfo(int ID, string GroupName, string RoleName, int SiteIdx, int ParentIdx, int InheritKind, string Description)
        {
            this.ID = ID;
            this.GroupName = GroupName;
            this.RoleName = RoleName;
            this.SiteIdx = SiteIdx;
            this.ParentIdx = ParentIdx;
            this.InheritKind = InheritKind;
            this.Description = Description;
        }
        #endregion
        #region "Public Properties"
        /// <summary>序号</summary>
        [Required]
        [Display(Name = "序号")]
        public int ID { get; set; }
        /// <summary>组名称</summary>
        [Display(Name = "组名称")]
        public string GroupName { get; set; }
        /// <summary>角色名称</summary>
        [Display(Name = "角色名称")]
        public string RoleName { get; set; }
        /// <summary>站点序号</summary>
        [Required]
        [Display(Name = "站点序号")]
        public int SiteIdx { get; set; }
        /// <summary>上级节点</summary>
        [Required]
        [Display(Name = "上级节点")]
        public int ParentIdx { get; set; }
        /// <summary>继承关系</summary>
        [Display(Name = "继承关系")]
        public int InheritKind { get; set; }
        /// <summary>角色说明</summary>
        [Display(Name = "角色说明")]
        public string Description { get; set; }

        #endregion
    }
}
#endregion
//功能权限控制(PTL_ActionRight)
#region "功能权限控制信息类声明"
namespace VonPortal.Web.Models
{
    /// <summary>功能权限控制 信息类</summary>
    public class ActionRightInfo
    {
        #region "Constructors"
        /// <summary>
        /// 构造函数
        /// </summary>
        public ActionRightInfo()
        {
        }
        /// <summary>
        /// 含初始化构造函数
        /// </summary>
        /// <param name="ID">序号</param>
        /// <param name="SiteIdx">站点序号</param>
        /// <param name="RightName">功能名称</param>
        /// <param name="RoleOrUser">角色或用户序号</param>
        /// <param name="SrcIdx">控制源序号</param>
        public ActionRightInfo(int ID, int SiteIdx, string RightName, bool RoleOrUser, int SrcIdx)
        {
            this.ID = ID;
            this.SiteIdx = SiteIdx;
            this.RightName = RightName;
            this.RoleOrUser = RoleOrUser;
            this.SrcIdx = SrcIdx;
        }
        #endregion
        #region "Public Properties"
        /// <summary>序号</summary>
        [Required]
        [Display(Name = "序号")]
        public int ID { get; set; }
        /// <summary>站点序号</summary>
        [Required]
        [Display(Name = "站点序号")]
        public int SiteIdx { get; set; }
        /// <summary>功能名称</summary>
        [Display(Name = "功能名称")]
        public string RightName { get; set; }
        /// <summary>角色或用户序号</summary>
        [Required]
        [Display(Name = "角色或用户序号")]
        public bool RoleOrUser { get; set; }
        /// <summary>控制源序号</summary>
        [Required]
        [Display(Name = "控制源序号")]
        public int SrcIdx { get; set; }
        #endregion
    }
}
#endregion

其控制与数据库存储的类,这里就省略了,首先大家知道,要实现这个方案,作为基础的信息基类,就是这三个类即,UserInfo、RoleInfo、ActionRightInfo。

我们下面就进入今天的主题,如何通过建立自己的AuthorizeAttribute特性来实现角色控制。

我们先来分析一下AuthorizeAttribute的执行过程。在特性指定到系统的某一个模块上时,即为某一个 Controller 指定一个我们自己的权限认证特性,指定后,当系统执行时,系统就会调用 AuthorizeAttribute 中的 OnAuthorization 函数来完成,在 OnAuthorization 函数的执行过程中,系统会调用 bool AuthorizeCore(HttpContextBase httpContext) 函数完成具体的验证过程,如果失败了,系统会调用 void HandleUnauthorizedRequest(AuthorizationContext context)来进行处理,由此我们就可以建立一个自己的 AuthorizeAttribute 

/******************************************************************************************************************
* 权限验证单元
*   RightAuthorizeAttribute 是继承 AuthorizeAttribute 的权限控制属性,他是基于功能的权限认证模式,即采用功能名称
*   进行认证,认证过程基于 AuthorizeAttribute 进行,首先系统会调用 OnAuthorization 进行验证,在这里我们主要进行
*   验证前准备,
****************************************************************************************************************/
using System;
using System.Threading.Tasks;
using Microsoft.AspNet.Identity;
using Microsoft.AspNet.Identity.Owin;
using Microsoft.Owin.Security;
using System.Web.Mvc;
using System.Web.Routing;
using System.Web;
using System.Collections.Generic;
using VonPortal.Web.Operators;

namespace VonPortal.Web.Models
{
    /// <summary>
    /// 权限控制单元
    /// </summary>
    public class RightAuthorizeAttribute : AuthorizeAttribute
    {
        /// <summary>
        /// 功能名称
        /// </summary>
        public string ActionNames { get; set; }
        private string moduleName = "";
        public override void OnAuthorization(AuthorizationContext filterContext)
        {
            string controllerName = filterContext.ActionDescriptor.ControllerDescriptor.ControllerName;
            string actionName = filterContext.ActionDescriptor.ActionName;
            moduleName = controllerName + '/' + actionName;
            base.OnAuthorization(filterContext);
        }
        protected override bool AuthorizeCore(HttpContextBase httpContext)
        {
            bool result = false;
            if (httpContext == null)
                throw new ArgumentNullException("HttpContext");
            if (!httpContext.User.Identity.IsAuthenticated)
                return false;
            // 得到用户的唯一序号
            int userIdx = httpContext.User.Identity.GetUserId<int>();
            List<int> roles = (new UserRoleCtrl(null)).ListByROLE_REF_USER(userIdx);
            #region "检测 Roles 即,检测指定的 Role 是否存在,如果设定了,但不存在则表明无权访问。"
            if (Roles != null && Roles.Length > 0)
            {
                string authRole = "," + Roles.ToLower() + ",";
                result = false;
                foreach (int roleIdx in roles)
                {
                    RoleInfo role = (new RoleCtrl(null)).GetByRole(roleIdx);
                    result = role != null && authRole.IndexOf("," + role.RoleName.ToLower() + ",") >= 0;
                    if (result) break;
                }
                if (!result) return false;
            }
            #endregion
            #region "检测 Users 即,检测指定的 Users 是否存在,如果设定了,但不存在则表明无权访问。"
            string userName = httpContext.User.Identity.GetUserName();
            if (Users != null && Users.Length > 0)
            {
                if (("," + Users.ToLower() + ",").IndexOf("," + userName.ToLower() + ",") < 0)
                    return false;
                result = true;
            }
            #endregion
            #region "检测 ActionNames 即,检测指定的 ActionNames 是否存在,如果设定了,但不存在则表明无权访问。"
            if (ActionNames != null && ActionNames.Length > 0)
            {
                string authAction = "," + ActionNames.ToLower() + ","; 
                // 检测用户本身是否具备该功能的权限
                foreach (ActionRightInfo right in (new ActionRightCtrl(null)).ListBySrcIdx(true, userIdx))
                {
                    if (ActionNames.IndexOf("," + right.RightName + ",") >= 0) return true;
                }
                // 检测用户拥有的角色本身是否具备该功能的权限
                foreach (int roleIdx in roles)
                {
                    foreach (ActionRightInfo right in (new ActionRightCtrl(null)).ListBySrcIdx(false, roleIdx))
                    {
                        if (ActionNames.IndexOf("," + right.RightName + ",") >= 0) return true;
                    }
                }
            }
            else if (!result)
            {
                string authAction = "," + moduleName.ToLower() + ",";
                // 检测用户本身是否具备该功能的权限
                foreach (ActionRightInfo right in (new ActionRightCtrl(null)).ListBySrcIdx(true, userIdx))
                {
                    if (ActionNames.IndexOf("," + right.RightName + ",") >= 0) return true;
                }
                // 检测用户拥有的角色本身是否具备该功能的权限
                foreach (int roleIdx in roles)
                {
                    foreach (ActionRightInfo right in (new ActionRightCtrl(null)).ListBySrcIdx(false, roleIdx))
                    {
                        if (ActionNames.IndexOf("," + right.RightName + ",") >= 0) return true;
                    }
                }
            }
            #endregion
            return result;
        }
        protected override void HandleUnauthorizedRequest(AuthorizationContext context)
        {
            if (context == null)
            {
                throw new ArgumentNullException("filterContext");
            }
            else
            {
                string path = context.HttpContext.Request.Path;
                string strUrl = "/Account/Login?returnUrl={0}";
                context.HttpContext.Response.Redirect(string.Format(strUrl, HttpUtility.UrlEncode(path)), true);
            }
        }
    }
}

使用方法:

在Controller中的Action使用前增加我们的RightAuthorize的特性就可以了。

1、指定功能名称验证用户权限:

        [RightAuthorize(ActionNames = "UserManager")]

        public ActionResult UserList(...){...}

2、指定角色名称证用户权限:

        [RightAuthorize(Roles = "Admin")]

        public ActionResult UserDetails(...){...}

3、指定用户名称证用户权限:

        [RightAuthorize(Users = "Administrator,Host")]

        public ActionResult UserEdit(...){...}

4、默认通过Controller+Action来验证用户权限:默认的功能名称是ControllerName/ActionName

        [RightAuthorize()]

        public ActionResult UserDelete(...){...}


© 著作权归作者所有

共有 人打赏支持
jamesvon
粉丝 3
博文 31
码字总数 47875
作品 0
河西
项目经理
Lind.DDD.Authorization用户授权介绍

Lind.DDD.Authorization是Lind.DDD框架的组成部分,之所以把它封装到框架里,原因就是它的通用性,几乎在任何一个系统中,都少不了用户授权功能,用户授权对于任何一个系统来说都是必要的,像...

mcy247 ⋅ 2017/12/06 ⋅ 0

爱上MVC~AuthorizeAttribute验证不通过如何停止当前上下文

我们知道mvc里有一些过滤器,AuthorizeAttribute用来做授权,一般在用户授权方面可以使用它,当使用没有登陆,我们直接跳到登陆页,这是没有问题的,可我要说的是,当用户对某个Action没有权...

mcy247 ⋅ 2017/12/06 ⋅ 0

认识ASP.NET MVC的5种AuthorizationFilter

在总体介绍了筛选器及其提供机制(《深入探讨ASP.NET MVC的筛选器》)之后,我们按照执行的先后顺序对四种不同的筛选器进行单独介绍,首先来介绍最先执行的AuthorizationFilter。从命名来看,...

长平狐 ⋅ 2012/09/04 ⋅ 0

ASP.NET MVC 基于角色的权限控制系统的示例教程

上一次在 .NET MVC 用户权限管理示例教程中讲解了ASP.NET MVC 通过AuthorizeAttribute类的OnAuthorization方法讲解了粗粒度控制权限的方法,接下来讲解基于角色的权限控制方法。 基于角色的权...

鱼煎 ⋅ 2015/08/19 ⋅ 0

Sharepoint2013权限管理之老王乱弹一

最近和一些搞SharePoint的朋友在一起交流了一些关于SharePoint2013权限控制的东西,发现很多朋友对于SharePoint的权限控制,认识的不是很清晰,比如说如何通过SharePoint实现,用户可以查看但...

科技小能手 ⋅ 2017/11/12 ⋅ 0

政府站群:基层生产内容,群众的力量是伟大的

一.大部分政府网站的现状 政府网站的内容维护的重担往往在“信息办”等机构里,靠着有限的人员编制,“定期”发布一些信息上去,所以,政府网站很容易沦为“面子工程”,而没有多少实际用处...

stormspeaker ⋅ 2014/01/16 ⋅ 0

创易网站内容管理系统--CreateEasy

产品介绍: 创易网站内容管理系统,英文全称为CreateEasy Content Management System,简称创易CMS或CECMS(以下简称创易CMS)。CreateEasy CMS 是一套面向各类中小型站点建设和管理而设计研发的...

cecms ⋅ 2009/11/27 ⋅ 0

网站群建设-->营造自己的网络圈品牌

一.浅谈百度、360圈 念书的时候,由于本身学得是计算机专业,如果要学好的话,听老师讲很有限,那会流行的用语就是‘百度一下你就知道’;到了上班工作了,碰到啥技术问题,找相关专业的技术...

stormspeaker ⋅ 2013/07/24 ⋅ 0

MVC3中使用AuthorizeAttribute特性来完成登陆权限的验证

过去的过去,往往对于一种问题有一个很直观的解决方法,如,判断用户是否登陆,判断用户session是否为空,一般会这个写在页面中: if(HttpContext.Session.IsNewSession){// go to Logon} 每...

mcy247 ⋅ 2017/12/04 ⋅ 0

省级网站群建设关注点

省级网站群建设关注点 任何一个省级网站群建设都有各自的核心理念和关注点,综合近几年在这方面的工作和尝试,将省级网站群建设的关注点分享一下。 一、建立统一的技术支撑与管理平台,为网站...

yztxw ⋅ 2014/12/11 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

Jenkins实践3 之脚本

#!/bin/sh# export PROJ_PATH=项目路径# export TOMCAT_PATH=tomcat路径killTomcat(){pid=`ps -ef | grep tomcat | grep java|awk '{print $2}'`echo "tom...

晨猫 ⋅ 今天 ⋅ 0

Spring Bean的生命周期

前言 Spring Bean 的生命周期在整个 Spring 中占有很重要的位置,掌握这些可以加深对 Spring 的理解。 首先看下生命周期图: 再谈生命周期之前有一点需要先明确: Spring 只帮我们管理单例模...

素雷 ⋅ 今天 ⋅ 0

zblog2.3版本的asp系统是否可以超越卢松松博客的流量[图]

最近访问zblog官网,发现zlbog-asp2.3版本已经进入测试阶段了,虽然正式版还没有发布,想必也不久了。那么作为aps纵横江湖十多年的今天,blog2.2版本应该已经成熟了,为什么还要发布这个2.3...

原创小博客 ⋅ 今天 ⋅ 0

聊聊spring cloud的HystrixCircuitBreakerConfiguration

序 本文主要研究一下spring cloud的HystrixCircuitBreakerConfiguration HystrixCircuitBreakerConfiguration spring-cloud-netflix-core-2.0.0.RELEASE-sources.jar!/org/springframework/......

go4it ⋅ 今天 ⋅ 0

二分查找

二分查找,也称折半查找、二分搜索,是一种在有序数组中查找某一特定元素的搜索算法。搜素过程从数组的中间元素开始,如果中间元素正好是要查找的元素,则搜素过程结束;如果某一特定元素大于...

人觉非常君 ⋅ 今天 ⋅ 0

VS中使用X64汇编

需要注意的是,在X86项目中,可以使用__asm{}来嵌入汇编代码,但是在X64项目中,再也不能使用__asm{}来编写嵌入式汇编程序了,必须使用专门的.asm汇编文件来编写相应的汇编代码,然后在其它地...

simpower ⋅ 今天 ⋅ 0

ThreadPoolExecutor

ThreadPoolExecutor public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, ......

4rnold ⋅ 昨天 ⋅ 0

Java正无穷大、负无穷大以及NaN

问题来源:用Java代码写了一个计算公式,包含除法和对数和取反,在页面上出现了-infinity,不知道这是什么问题,网上找答案才明白意思是负的无穷大。 思考:为什么会出现这种情况呢?这是哪里...

young_chen ⋅ 昨天 ⋅ 0

前台对中文编码,后台解码

前台:encodeURI(sbzt) 后台:String param = URLDecoder.decode(sbzt,"UTF-8");

west_coast ⋅ 昨天 ⋅ 0

实验楼—MySQL基础课程-挑战3实验报告

按照文档要求创建数据库 sudo sercice mysql startwget http://labfile.oss.aliyuncs.com/courses/9/createdb2.sqlvim /home/shiyanlou/createdb2.sql#查看下数据库代码 代码创建了grade......

zhangjin7 ⋅ 昨天 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部