你的位置:首页 > ASP.net教程

[ASP.net教程]【无私分享:从入门到精通ASP.NET MVC】从0开始,一起搭框架、做项目(6) 控制器基类 主要做登录用户、权限认证、日志记录等工作

声明:本系列为原创,分享本人现用框架,未经本人同意,禁止转载!http://yuangang.cnblogs.com

希望大家好好一步一步做,所有的技术和项目,都毫无保留的提供,希望大家能自己跟着做一套,还有,请大家放心,只要大家喜欢,有人需要,绝对不会烂尾,我会坚持写完~

如果你感觉文章有帮助,点一下推荐,让更多的朋友参与进来,也是对本人劳动成果的鼓励,谢谢大家!由于还要工作,所以基本都是牺牲午休时间来写博客的,写博客呢不是简单的Ctrl+C、Ctrl+V,我是要挨着做一遍的,这也是对大家负责,所以有些时候更新不及时,或者问题没有及时解答,希望大家谅解,再次感谢大家!!

因为我引用了许多以前积累的类库,所以有些东西是重复的(后来更新),有些东西是过时的,包括我写的代码,希望大家不要纯粹的复制,取其精华去其糟粕>_<。

在项目最后我会把每个部分、每个阶段的Demo提供下载给大家,其实,如果跟着做完,并且剔除掉了我代码不好的地方,你也不需要这些Demo了,是吧~

索引

 【无私分享:从入门到精通ASP.NET MVC】从0开始,一起搭框架、做项目(1)搭建MVC环境 注册区域

 【无私分享:从入门到精通ASP.NET MVC】从0开始,一起搭框架、做项目(2)创建数据库和数据模型

 【无私分享:从入门到精通ASP.NET MVC】从0开始,一起搭框架、做项目(3)公共基础数据操作类 RepositoryBase

 【无私分享:从入门到精通ASP.NET MVC】从0开始,一起搭框架、做项目(4)对前面的一些问题汇总和总结

 【无私分享:从入门到精通ASP.NET MVC】从0开始,一起搭框架、做项目(5.1) 登录功能的实现,开始接触Spring IOC、DI

【无私分享:从入门到精通ASP.NET MVC】从0开始,一起搭框架、做项目(5.2) 登录功能的实现,接口注入、log4net的使用

【无私分享:从入门到精通ASP.NET MVC】从0开始,一起搭框架、做项目(5.3) 登录功能的实现,丰富数据表、建立关联

【无私分享:从入门到精通ASP.NET MVC】从0开始,一起搭框架、做项目(5.4) 登录功能的实现,创建与登录用户相关的接口和实现类

【无私分享:从入门到精通ASP.NET MVC】从0开始,一起搭框架、做项目(5.5) 登录功能的实现,完善登录功能

简述

今天我们来写一个控制器基类 主要做登录用户、权限认证、日志记录等工作

项目准备

我们用的工具是:VS 2013 + SqlServer 2012 + IIS7.5

希望大家对ASP.NET MVC有一个初步的理解,理论性的东西我们不做过多解释,有些地方不理解也没关系,会用就行了,用的多了,用的久了,自然就理解了。

项目开始

很多朋友在前几篇都遇到 根节点 的问题,我把这几个

WebPage/Config下面三个

ComControllers.

1 <?"1.0" encoding="utf-8" ?>2 <objects "http://www.springframework.net">3  <description>Spring注入控制器,容器指向Service层封装的接口</description>4 </objects>

View Code

Controllers.

 1 <?"1.0" encoding="utf-8" ?> 2 <objects "http://www.springframework.net"> 3  <description>Spring注入控制器,容器指向Service层封装的接口</description> 4  <!--系统管理 Begin--> 5  <!--登录控制器--> 6  <object type="WebPage.Areas.SysManage.Controllers.AccountController,WebPage" singleton="false"> 7   <property name="UserManage" ref="Service.User"/> 8  </object> 9  <!--系统管理 end-->10 </objects>

View Code

Service/Config下面两个

ComService.

1 <?"1.0" encoding="utf-8" ?>2 <objects "http://www.springframework.net">3  <description>Spring注入Service,容器指向本层层封装的接口,舍弃Dao层,减少代码量</description>4 </objects>

View Code

Service.

1 <?"1.0" encoding="utf-8" ?>2 <objects "http://www.springframework.net">3  <description>Spring注入Service,容器指向本层层封装的接口,舍弃Dao层,减少代码量</description>4  <!--系统管理begin-->5  <!--用户管理-->6  <object id="Service.User" type="Service.ServiceImp.UserManage,Service" singleton="false">7  </object>8  <!--系统管理end-->9 </objects>

View Code

 

一、我们在Controllers文件夹下新建一个控制器 BaseController, 用于控制器基类,主要做登录用户、权限认证、日志记录等工作

 

二、我们声明一些公共变量和容器

变量主要用于我们查询分页的时候用户传递关键字、页码和分页条数

这个用户容器 主要是用户后台用户的一些操作

 1 #region 公用变量 2     /// <summary> 3     /// 查询关键词 4     /// </summary> 5     public string keywords { get; set; } 6     /// <summary> 7     /// 视图传递的分页页码 8     /// </summary> 9     public int page { get; set; }10     /// <summary>11     /// 视图传递的分页条数12     /// </summary>13     public int pagesize { get; set; }14     /// <summary>15     /// 用户容器,公用16     /// </summary>17     public IUserManage UserManage = Spring.Context.Support.ContextRegistry.GetContext().GetObject("Service.User") as IUserManage;18 #endregion

 

三、获取当前用户对象

从Sesssion中获取用户对象,Session过期后 通过 Cookies重新获取用户对象

 1     #region 用户对象 2     /// <summary> 3     /// 获取当前用户对象 4     /// </summary> 5     public Account CurrentUser 6     { 7       get 8       { 9         //从Session中获取用户对象10         if (SessionHelper.GetSession("CurrentUser") != null)11         {12           return SessionHelper.GetSession("CurrentUser") as Account;13         }14         //Session过期 通过Cookies中的信息 重新获取用户对象 并存储于Session中15         var account = UserManage.GetAccountByCookie();16         SessionHelper.SetSession("CurrentUser", account);17         return account;18       }19     }20     #endregion

 

四、重写控制器 OnActionExecuting(ActionExecutingContext filterContext)方法 实现登录验证和公共变量的获取

 protected override void OnActionExecuting(ActionExecutingContext filterContext)

 1 #region 登录用户验证 2       //1、判断Session对象是否存在 3       if (filterContext.HttpContext.Session == null) 4       { 5         filterContext.HttpContext.Response.Write( 6            " <script type='text/javascript'> alert('~登录已过期,请重新登录');window.top.location='/'; </script>"); 7         filterContext.RequestContext.HttpContext.Response.End(); 8         filterContext.Result = new EmptyResult(); 9         return;10       }11       //2、登录验证12       if (this.CurrentUser == null)13       {14         filterContext.HttpContext.Response.Write(15           " <script type='text/javascript'> alert('登录已过期,请重新登录'); window.top.location='/';</script>");16         filterContext.RequestContext.HttpContext.Response.End();17         filterContext.Result = new EmptyResult();18         return;19       }20 21 #endregion

 1 #region 公共Get变量 2       //分页页码 3       object p = filterContext.HttpContext.Request["page"]; 4       if (p == null || p.ToString() == "") { page = 1; } else { page = int.Parse(p.ToString()); } 5  6       //搜索关键词 7       string search = filterContext.HttpContext.Request.QueryString["Search"]; 8       if (!string.IsNullOrEmpty(search)) { keywords = search; } 9       //显示分页条数10       string size = filterContext.HttpContext.Request.QueryString["example_length"];11       if (!string.IsNullOrEmpty(size) && System.Text.RegularExpressions.Regex.IsMatch(size.ToString(), @"^\d+$")) { pagesize = int.Parse(size.ToString()); } else { pagesize = 10; }12 #endregion

 

五、模块权限验证功能

规则:1、根据模块别名验证对应模块
        2、根据模块操作Action 验证是否可操作按钮

这里我们分为两个打步骤:第一,前台按钮没有相应操作权限的,我们移除前台操作按钮。

                                  第二,也是为了防止用户绕过前台验证,我们对后台模块以及方法进行验证,如果用户对相应的模块没有相应的操作权限(添加、修改、删除、审核、发布等等,包含自定义操作类型),我们拒绝执行。

网站的权限判断是一个非常普遍的需求,我们实现这样的需求只要从 AuthorizeAttribute 集成,重写相关的判断逻辑

我们新建一个权限验证类UserAuthorizeAttribute 继承 AuthorizeAttribute (关于AuthorizeAttribute 点击这里)

public class UserAuthorizeAttribute : AuthorizeAttribute

 

我们对添加一个自定义的Attribute,通过AttributeUsage的Attribute来限定Attribute 所施加的元素的类型

作为参数的AttributeTarges的值允许通过“或”操作来进行多个值得组合,如果你没有指定参数,那么默认参数就是All 。

AttributeUsage除了继承Attribute 的方法和属性之外,还定义了以下三个属性:

AllowMultiple: 读取或者设置这个属性,表示是否可以对一个程序元素施加多个Attribute 。

Inherited:读取或者设置这个属性,表示是否施加的Attribute 可以被派生类继承或者重载。

ValidOn: 读取或者设置这个属性,指明Attribute 可以被施加的元素的类型。

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false)]public class UserAuthorizeAttribute : AuthorizeAttribute{
}

 

添加一些字段和属性,并且实例化基类

 1 #region 字段和属性 2     /// <summary> 3     /// 模块别名,可配置更改 4     /// </summary> 5     public string ModuleAlias { get; set; } 6     /// <summary> 7     /// 权限动作 8     /// </summary> 9     public string OperaAction { get; set; }10     /// <summary>11     /// 权限访问控制器参数12     /// </summary>13     private string Sign { get; set; }14     /// <summary>15     /// 基类实例化16     /// </summary>17     public BaseController baseController = new BaseController();18 19 #endregion

 

我们重写 AuthorizeAttribute 的 OnAuthorization(AuthorizationContext filterContext)方法

1     /// <summary>2     /// 权限认证3     /// </summary>4     public override void OnAuthorization(AuthorizationContext filterContext)5     {6     }

 

分为四步:

1、判断模块是否对应

2、判断用户是否存在

3、调用下面的方法,验证是否有访问此页面的权限,查看加操作

4、有权限访问页面,将此页面的权限集合传给页面

1       //1、判断模块是否对应2       if (string.IsNullOrEmpty(ModuleAlias))3       {4         filterContext.HttpContext.Response.Write(" <script type='text/javascript'> alert('^您没有访问该页面的权限!'); </script>");5         filterContext.RequestContext.HttpContext.Response.End();6         filterContext.Result = new EmptyResult();7         return;8       }

1       //2、判断用户是否存在2       if (baseController.CurrentUser == null)3       {4         filterContext.HttpContext.Response.Write(" <script type='text/javascript'> alert('^登录已过期,请重新登录!');window.top.location='/'; </script>");5         filterContext.RequestContext.HttpContext.Response.End();6         filterContext.Result = new EmptyResult();7         return;8       }

 1       //对比变量,用于权限认证 2       var alias = ModuleAlias; 3  4       #region 配置Sign调取控制器标识 5       Sign = filterContext.RequestContext.HttpContext.Request.QueryString["sign"]; 6       if (!string.IsNullOrEmpty(Sign)) 7       { 8         if (("," + ModuleAlias.ToLower()).Contains("," + Sign.ToLower())) 9         {10           alias = Sign;11           filterContext.Controller.ViewData["Sign"] = Sign;12         }13       }14       #endregion

 1       //3、调用下面的方法,验证是否有访问此页面的权限,查看加操作 2       var moduleId = baseController.CurrentUser.Modules.Where(p => p.ALIAS.ToLower() == alias.ToLower()).Select(p => p.ID).FirstOrDefault(); 3       bool _blAllowed = this.IsAllowed(baseController.CurrentUser, moduleId, OperaAction); 4       if (!_blAllowed) 5       { 6         filterContext.HttpContext.Response.Write(" <script type='text/javascript'> alert('您没有访问当前页面的权限!');</script>"); 7         filterContext.RequestContext.HttpContext.Response.End(); 8         filterContext.Result = new EmptyResult(); 9         return;10       }

1       //4、有权限访问页面,将此页面的权限集合传给页面2       filterContext.Controller.ViewData["PermissionList"] = GetPermissByJson(baseController.CurrentUser, moduleId);

 

上面主要是对后台控制器方法操作权限的验证,有时候前台展示了比如 添加、删除功能,但是用户去操作的时候后台验证不通过会提示用户没有操作权限,这样显得不是很友好,我们返回个权限Json,前台按钮没有这个权限的我们就移除掉

1     /// <summary>2     /// 获取操作权限Json字符串,供视图JS判断使用3     /// </summary>4     string GetPermissByJson(Account account, int moduleId)5     {6       //操作权限7       var _varPerListThisModule = account.Permissions.Where(p => p.MODULEID == moduleId).Select(R => new { R.PERVALUE }).ToList();8       return Common.JsonConverter.Serialize(_varPerListThisModule);9     }

 1     /// <summary> 2     /// 功能描述:判断用户是否有此模块的操作权限 3     /// </summary> 4     bool IsAllowed(Account user, int moduleId, string action) 5     { 6       //判断入口 7       if (user == null || user.Id <= 0 || moduleId == 0 || string.IsNullOrEmpty(action)) return false; 8       //验证权限 9       var permission = user.Permissions.Where(p => p.MODULEID == moduleId);10       action = action.Trim(',');11       if (action.IndexOf(',') > 0)12       {13         permission = permission.Where(p => action.ToLower().Contains(p.PERVALUE.ToLower()));14       }15       else16       {17         permission = permission.Where(p => p.PERVALUE.ToLower() == action.ToLower());18       }19       return permission.Any();20     }

 

模块去重

 1   /// <summary> 2   /// 模型去重,非常重要 3   /// add yuangang by 2016-05-25 4   /// </summary> 5   public class ModuleDistinct : IEqualityComparer<Domain.SYS_MODULE> 6   { 7     public bool Equals(Domain.SYS_MODULE x, Domain.SYS_MODULE y) 8     { 9       return x.ID == y.ID;10     }11 12     public int GetHashCode(Domain.SYS_MODULE obj)13     {14       return obj.ToString().GetHashCode();15     }16   }

 

后面,我们就用到这个基类,我先给大家看一下这个权限认证在后台是如何使用的,加上这一句就OK了

 

 

 

原创文章 转载请尊重劳动成果 http://yuangang.cnblogs.com