ASP.NET MVC:窗体身份验证及角色权限管理示例
ASP.NET MVC 建立 ASP.NET 基础之上,很多 ASP.NET 的特性(如窗体身份验证、成员资格)在 MVC 中可以直接使用。本文旨在提供可参考的代码,不会涉及这方面太多理论的知识。
本文仅使用 ASP.NET 的窗体身份验证,不会使用它的 成员资格(Membership) 和 角色管理 (RoleManager),原因有二:一是不灵活,二是和 MVC 关系不太。
一、示例项目
User.cs 是模型文件,其中包含了 User 类:
- public class User
- {
- public int ID { get; set; }
- public string Name { get; set; }
- public string Password { get; set; }
- public string[] Roles { get; set; }
- }
UserRepository 为数据存取类,为了演示方便,并没有连接数据库,而是使用一个数组来作为数据源:
- public class UserRepository
- {
- private static User[] usersForTest = new[]{
- new User{ ID = 1, Name = "bob", Password = "bob", Roles = new []{"employee"}},
- new User{ ID = 2, Name = "tom", Password = "tom", Roles = new []{"manager"}},
- new User{ ID = 3, Name = "admin", Password = "admin", Roles = new[]{"admin"}},
- };
- public bool ValidateUser(string userName, string password)
- {
- return usersForTest
- .Any(u => u.Name == userName && u.Password == password);
- }
- public string[] GetRoles(string userName)
- {
- return usersForTest
- .Where(u => u.Name == userName)
- .Select(u => u.Roles)
- .FirstOrDefault();
- }
- public User GetByNameAndPassword(string name, string password)
- {
- return usersForTest
- .FirstOrDefault(u => u.Name == name && u.Password == password);
- }
- }
二、用户登录及身份验证
方式一
修改 AccountController:原有 AccountController 为了实现控制反转,对窗体身份验证进行了抽象。为了演示方便,我去除了这部分(以及注册及修改密码部分):
- public class AccountController : Controller
- {
- private UserRepository repository = new UserRepository();
- public ActionResult LogOn()
- {
- return View();
- }
- [HttpPost]
- public ActionResult LogOn(LogOnModel model, string returnUrl)
- {
- if (ModelState.IsValid)
- {
- if (repository.ValidateUser(model.UserName, model.Password))
- {
- FormsAuthentication.SetAuthCookie(model.UserName, model.RememberMe);
- if (!String.IsNullOrEmpty(returnUrl)) return Redirect(returnUrl);
- else return RedirectToAction("Index", "Home");
- }
- else
- ModelState.AddModelError("", "用户名或密码不正确!");
- }
- return View(model);
- }
- public ActionResult LogOff()
- {
- FormsAuthentication.SignOut();
- return RedirectToAction("Index", "Home");
- }
- }
修改 Global.asax:
- public class MvcApplication : System.Web.HttpApplication
- {
- public MvcApplication()
- {
- AuthorizeRequest += new EventHandler(MvcApplication_AuthorizeRequest);
- }
- void MvcApplication_AuthorizeRequest(object sender, EventArgs e)
- {
- IIdentity id = Context.User.Identity;
- if (id.IsAuthenticated)
- {
- var roles = new UserRepository().GetRoles(id.Name);
- Context.User = new GenericPrincipal(id, roles);
- }
- }
- //...
- }
给 MvcApplication 增加构造函数,在其中增加 AuthorizeRequest 事件的处理函数。
方式二
此方式将用户的角色保存至用户 Cookie,使用到了 FormsAuthenticationTicket。
修改 AccountController:
- public class AccountController : Controller
- {
- private UserRepository repository = new UserRepository();
- public ActionResult LogOn()
- {
- return View();
- }
- [HttpPost]
- public ActionResult LogOn(LogOnModel model, string returnUrl)
- {
- if (ModelState.IsValid)
- {
- User user = repository.GetByNameAndPassword(model.UserName, model.Password);
- if (user != null)
- {
- FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(
- 1,
- user.Name,
- DateTime.Now,
- DateTime.Now.Add(FormsAuthentication.Timeout),
- model.RememberMe,
- user.Roles.Aggregate((i,j)=>i+","+j)
- );
- HttpCookie cookie = new HttpCookie(
- FormsAuthentication.FormsCookieName,
- FormsAuthentication.Encrypt(ticket));
- Response.Cookies.Add(cookie);
- if (!String.IsNullOrEmpty(returnUrl)) return Redirect(returnUrl);
- else return RedirectToAction("Index", "Home");
- }
- else
- ModelState.AddModelError("", "用户名或密码不正确!");
- }
- return View(model);
- }
- public ActionResult LogOff()
- {
- FormsAuthentication.SignOut();
- return RedirectToAction("Index", "Home");
- }
- }
修改 Global.asax:
- public class MvcApplication : System.Web.HttpApplication
- {
- public MvcApplication()
- {
- AuthorizeRequest += new EventHandler(MvcApplication_AuthorizeRequest);
- }
- void MvcApplication_AuthorizeRequest(object sender, EventArgs e)
- {
- var id = Context.User.Identity as FormsIdentity;
- if (id != null && id.IsAuthenticated)
- {
- var roles = id.Ticket.UserData.Split(',');
- Context.User = new GenericPrincipal(id, roles);
- }
- }
- //...
- }
三、角色权限
使用任一种方式后,我们就可以在 Controller 中使用 AuthorizeAttribute 实现基于角色的权限管理了:
- [Authorize(Roles = "employee,manager")]
- public ActionResult Index1()
- {
- return View();
- }
- [Authorize(Roles = "manager")]
- public ActionResult Index2()
- {
- return View();
- }
- [Authorize(Users="admin", Roles = "admin")]
- public ActionResult Index3()
- {
- return View();
- }
四、简要说明
MVC 使用 HttpContext.User 属性进行来进行实现身份验证及角色管理,同样 AuthorizeAttribute 也根据 HttpContext.User 进行角色权限验证。
因些不要在用户登录后,将相关用户信息保存在 Session 中(网上经常看到这种做法),将用户保存在 Session 中是一种非常不好的做法。
也不要在 Action 中进行角色权限判断,应该使用 AuthorizeAttribute 或它的子类,以下的方式都是错误的:
- public ActionResult Action1()
- {
- if (Session["User"] == null) { /**/}
- /**/
- }
- public ActionResult Action2()
- {
- if (User.Identity == null) { /**/}
- if (User.Identity.IsAuthenticated == false) { /**/}
- if (User.IsInRole("admin") == false) { /**/}
- /**/
- }
ASP.NET MVC:窗体身份验证及角色权限管理示例的更多相关文章
- ASP.NET MVC Cookie 身份验证
1 创建一个ASP.NET MVC 项目 添加一个 AccountController 类. public class AccountController : Controller { [HttpGe ...
- Asp.Net Mvc通用后台管理系统,bootstrap+easyui+权限管理+ORM
产品清单: 1.整站源码,非编译版,方便进行业务的二次开发 2.通用模块与用户等基础数据的数据库脚本 3.bootstrap3.3.1 AceAdmin模板源码 4.easyui1.3.5源码 5.F ...
- asp.net mvc 自定义身份验证
1.定义身份实体对象 /// <summary> /// 网站用户实体对象 /// </summary> public class DDTPrincipal : IPrinci ...
- asp.net mvc 自定义身份验证 2
控制成员角色 [Authorize(Rroles="Administator,SuperAdmin")] public class StoreManagerController:C ...
- Asp.net中基于Forms验证的角色验证授权
Asp.net的身份验证有有三种,分别是"Windows | Forms | Passport",其中又以Forms验证用的最多,也最灵活. Forms 验证方式对基于用户的验证授 ...
- 如何通过使用窗体身份验证和 Visual C#.NET 对 Active Directory 验证身份
本分步指南演示如何在 ASP.NET 应用程序如何使用窗体身份验证允许用户使用轻型目录访问协议 (LDAP),对 Active Directory 进行验证.经过身份验证的用户重定向之后,可以使用Ap ...
- ASP.NET中的身份验证有那些?你当前项目采用什么方式验证请解释
ASP.NET身份验证模式包括Windows.Forms(窗体).Passport(护照)和None(无). l Windows身份验证—常结合应用程序自定义身份验证使用使用这种身份验证模式时,AS ...
- 采用Asp.Net的Forms身份验证时,非持久Cookie的过期时间会自动扩展
问题描述 之前没有使用Forms身份验证时,如果在登陆过程中把HttpOnly的Cookie过期时间设为半个小时,总会收到很多用户的抱怨,说登陆一会就过期了. 所以总是会把Cookie过期时间设的长一 ...
- 也谈Asp.net 中的身份验证
钱李峰 的这篇博文<Asp.net中的认证与授权>已对Asp.net 中的身份验证进行了不错实践.而我这篇博文,是从初学者的角度补充了一些基础的概念,以便能有个清晰的认识. 一.配置安全身 ...
随机推荐
- Android对话框之dismiss和cancel和hide区别
在我们看来两者效果都是一样的,其实看下源码就知道cancel肯定会去调dismiss的,如果调用的cancel的话就可以监听DialogInterface.OnCancelListener. /** ...
- ffmpeg 中 swscale 的用法
http://www.guguclock.com/2009/12/ffmpeg-swscale.html 如果想將某個PixelFormat轉換至另一個PixelFormat,例如,將YUV420P轉 ...
- [转]YII2 常用数据库操作
1.对象操作: //1.简单查询 $admin=Admin::model()->findAll($condition,$params); $admin=Admin::model()->fi ...
- hybrid开发设计
hybrid方案背景 大部分业务都是在不停改变的,我们希望native不发布新版本就可以让线上用户使用新功能.我们要实现这样的方式,采用h5来实现就可以满足这一要求,准确说是native里提供一个装载 ...
- 【转载】linux内核启动android文件系统过程分析
主要介绍linux 内核启动过程以及挂载android 根文件系统的过程,以及介绍android 源代码中文件系统部分的浅析. 主要源代码目录介绍Makefile (全局的Makefile)bioni ...
- 有了Hadoop MapReduce, 为什么还要Spark?
a. 由于MapReduce的shuffle过程需写磁盘,比较影响性能:而Spark利用RDD技术,计算在内存中进行. b. MapReduce计算框架(API)比较局限, 而Spark则是具备灵活性 ...
- Android应用安全之Content Provider安全
android平台提供了Content Provider,将一个应用程序的指定数据集提供给其它应用程序.这些数据可以存储在文件系统.SQLite数据库中,或以任何其它合理的方式存储.其他应用可以通过C ...
- Apk去签名校验详解
某些apk为了防止重打包,使用了签名校验.所以在破解的时候我们需要破解签名校验.在定位签名校验位置时常用的关键词有sign,signature,checkSign,signCheck,getPacka ...
- WCF安全2-非对称加密
概述: 数字签名和加密依赖于相应的加密算法 自变量:加密前的数据.密钥 因变量:加密后的数据 加密算法分类:根据加密和解密这两种步骤采用的密钥的是否相同进行分类 相同:对称加密 不相同:非对称加密 非 ...
- [Design Patterns] 4. Creation Pattern
设计模式是一套被反复使用.多数人知晓的.经过分类编目的.代码设计经验的总结,使用设计模式的目的是提高代码的可重用性,让代码更容易被他人理解,并保证代码可靠性.它是代码编制真正实现工程化. 四个关键元素 ...