ASP.NET MVC 建立 ASP.NET 基础之上,很多 ASP.NET 的特性(如窗体身份验证、成员资格)在 MVC 中可以直接使用。本文旨在提供可参考的代码,不会涉及这方面太多理论的知识。

本文仅使用 ASP.NET 的窗体身份验证,不会使用它的 成员资格(Membership) 和 角色管理 (RoleManager),原因有二:一是不灵活,二是和 MVC 关系不太。

一、示例项目

User.cs 是模型文件,其中包含了 User 类:

  1. public class User
  2. {
  3. public int ID { get; set; }
  4. public string Name { get; set; }
  5. public string Password { get; set; }
  6. public string[] Roles { get; set; }
  7. }

UserRepository 为数据存取类,为了演示方便,并没有连接数据库,而是使用一个数组来作为数据源:

  1. public class UserRepository
  2. {
  3. private static User[] usersForTest = new[]{
  4. new User{ ID = 1, Name = "bob", Password = "bob", Roles = new []{"employee"}},
  5. new User{ ID = 2, Name = "tom", Password = "tom", Roles = new []{"manager"}},
  6. new User{ ID = 3, Name = "admin", Password = "admin", Roles = new[]{"admin"}},
  7. };
  8.  
  9. public bool ValidateUser(string userName, string password)
  10. {
  11. return usersForTest
  12. .Any(u => u.Name == userName && u.Password == password);
  13. }
  14.  
  15. public string[] GetRoles(string userName)
  16. {
  17. return usersForTest
  18. .Where(u => u.Name == userName)
  19. .Select(u => u.Roles)
  20. .FirstOrDefault();
  21. }
  22.  
  23. public User GetByNameAndPassword(string name, string password)
  24. {
  25. return usersForTest
  26. .FirstOrDefault(u => u.Name == name && u.Password == password);
  27. }
  28. }

二、用户登录及身份验证

方式一

修改 AccountController:原有 AccountController 为了实现控制反转,对窗体身份验证进行了抽象。为了演示方便,我去除了这部分(以及注册及修改密码部分):

  1. public class AccountController : Controller
  2. {
  3. private UserRepository repository = new UserRepository();
  4.  
  5. public ActionResult LogOn()
  6. {
  7. return View();
  8. }
  9.  
  10. [HttpPost]
  11. public ActionResult LogOn(LogOnModel model, string returnUrl)
  12. {
  13. if (ModelState.IsValid)
  14. {
  15. if (repository.ValidateUser(model.UserName, model.Password))
  16. {
  17. FormsAuthentication.SetAuthCookie(model.UserName, model.RememberMe);
  18. if (!String.IsNullOrEmpty(returnUrl)) return Redirect(returnUrl);
  19. else return RedirectToAction("Index", "Home");
  20. }
  21. else
  22. ModelState.AddModelError("", "用户名或密码不正确!");
  23. }
  24. return View(model);
  25. }
  26.  
  27. public ActionResult LogOff()
  28. {
  29. FormsAuthentication.SignOut();
  30. return RedirectToAction("Index", "Home");
  31. }
  32. }

修改 Global.asax:

  1. public class MvcApplication : System.Web.HttpApplication
  2. {
  3. public MvcApplication()
  4. {
  5. AuthorizeRequest += new EventHandler(MvcApplication_AuthorizeRequest);
  6. }
  7.  
  8. void MvcApplication_AuthorizeRequest(object sender, EventArgs e)
  9. {
  10. IIdentity id = Context.User.Identity;
  11. if (id.IsAuthenticated)
  12. {
  13. var roles = new UserRepository().GetRoles(id.Name);
  14. Context.User = new GenericPrincipal(id, roles);
  15. }
  16. }
  17. //...
  18. }

给 MvcApplication 增加构造函数,在其中增加 AuthorizeRequest 事件的处理函数。

方式二

此方式将用户的角色保存至用户 Cookie,使用到了 FormsAuthenticationTicket。

修改 AccountController:

  1. public class AccountController : Controller
  2. {
  3. private UserRepository repository = new UserRepository();
  4.  
  5. public ActionResult LogOn()
  6. {
  7. return View();
  8. }
  9.  
  10. [HttpPost]
  11. public ActionResult LogOn(LogOnModel model, string returnUrl)
  12. {
  13. if (ModelState.IsValid)
  14. {
  15. User user = repository.GetByNameAndPassword(model.UserName, model.Password);
  16. if (user != null)
  17. {
  18. FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(
  19. 1,
  20. user.Name,
  21. DateTime.Now,
  22. DateTime.Now.Add(FormsAuthentication.Timeout),
  23. model.RememberMe,
  24. user.Roles.Aggregate((i,j)=>i+","+j)
  25. );
  26. HttpCookie cookie = new HttpCookie(
  27. FormsAuthentication.FormsCookieName,
  28. FormsAuthentication.Encrypt(ticket));
  29. Response.Cookies.Add(cookie);
  30.  
  31. if (!String.IsNullOrEmpty(returnUrl)) return Redirect(returnUrl);
  32. else return RedirectToAction("Index", "Home");
  33. }
  34. else
  35. ModelState.AddModelError("", "用户名或密码不正确!");
  36. }
  37. return View(model);
  38. }
  39.  
  40. public ActionResult LogOff()
  41. {
  42. FormsAuthentication.SignOut();
  43. return RedirectToAction("Index", "Home");
  44. }
  45. }

修改 Global.asax:

  1. public class MvcApplication : System.Web.HttpApplication
  2. {
  3. public MvcApplication()
  4. {
  5. AuthorizeRequest += new EventHandler(MvcApplication_AuthorizeRequest);
  6. }
  7.  
  8. void MvcApplication_AuthorizeRequest(object sender, EventArgs e)
  9. {
  10. var id = Context.User.Identity as FormsIdentity;
  11. if (id != null && id.IsAuthenticated)
  12. {
  13. var roles = id.Ticket.UserData.Split(',');
  14. Context.User = new GenericPrincipal(id, roles);
  15. }
  16. }
  17. //...
  18. }

三、角色权限

使用任一种方式后,我们就可以在 Controller 中使用 AuthorizeAttribute 实现基于角色的权限管理了:

  1. [Authorize(Roles = "employee,manager")]
  2. public ActionResult Index1()
  3. {
  4. return View();
  5. }
  6. [Authorize(Roles = "manager")]
  7. public ActionResult Index2()
  8. {
  9. return View();
  10. }
  11. [Authorize(Users="admin", Roles = "admin")]
  12. public ActionResult Index3()
  13. {
  14. return View();
  15. }

四、简要说明

MVC 使用 HttpContext.User 属性进行来进行实现身份验证及角色管理,同样 AuthorizeAttribute 也根据 HttpContext.User 进行角色权限验证。

因些不要在用户登录后,将相关用户信息保存在 Session 中(网上经常看到这种做法),将用户保存在 Session 中是一种非常不好的做法。

也不要在 Action 中进行角色权限判断,应该使用 AuthorizeAttribute 或它的子类,以下的方式都是错误的:

  1. public ActionResult Action1()
  2. {
  3. if (Session["User"] == null) { /**/}
  4. /**/
  5. }
  6. public ActionResult Action2()
  7. {
  8. if (User.Identity == null) { /**/}
  9. if (User.Identity.IsAuthenticated == false) { /**/}
  10. if (User.IsInRole("admin") == false) { /**/}
  11. /**/
  12. }

ASP.NET MVC:窗体身份验证及角色权限管理示例的更多相关文章

  1. ASP.NET MVC Cookie 身份验证

    1 创建一个ASP.NET MVC 项目 添加一个 AccountController 类. public class AccountController : Controller { [HttpGe ...

  2. Asp.Net Mvc通用后台管理系统,bootstrap+easyui+权限管理+ORM

    产品清单: 1.整站源码,非编译版,方便进行业务的二次开发 2.通用模块与用户等基础数据的数据库脚本 3.bootstrap3.3.1 AceAdmin模板源码 4.easyui1.3.5源码 5.F ...

  3. asp.net mvc 自定义身份验证

    1.定义身份实体对象 /// <summary> /// 网站用户实体对象 /// </summary> public class DDTPrincipal : IPrinci ...

  4. asp.net mvc 自定义身份验证 2

    控制成员角色 [Authorize(Rroles="Administator,SuperAdmin")] public class StoreManagerController:C ...

  5. Asp.net中基于Forms验证的角色验证授权

    Asp.net的身份验证有有三种,分别是"Windows | Forms | Passport",其中又以Forms验证用的最多,也最灵活. Forms 验证方式对基于用户的验证授 ...

  6. 如何通过使用窗体身份验证和 Visual C#.NET 对 Active Directory 验证身份

    本分步指南演示如何在 ASP.NET 应用程序如何使用窗体身份验证允许用户使用轻型目录访问协议 (LDAP),对 Active Directory 进行验证.经过身份验证的用户重定向之后,可以使用Ap ...

  7. ASP.NET中的身份验证有那些?你当前项目采用什么方式验证请解释

    ASP.NET身份验证模式包括Windows.Forms(窗体).Passport(护照)和None(无). l  Windows身份验证—常结合应用程序自定义身份验证使用使用这种身份验证模式时,AS ...

  8. 采用Asp.Net的Forms身份验证时,非持久Cookie的过期时间会自动扩展

    问题描述 之前没有使用Forms身份验证时,如果在登陆过程中把HttpOnly的Cookie过期时间设为半个小时,总会收到很多用户的抱怨,说登陆一会就过期了. 所以总是会把Cookie过期时间设的长一 ...

  9. 也谈Asp.net 中的身份验证

    钱李峰 的这篇博文<Asp.net中的认证与授权>已对Asp.net 中的身份验证进行了不错实践.而我这篇博文,是从初学者的角度补充了一些基础的概念,以便能有个清晰的认识. 一.配置安全身 ...

随机推荐

  1. Android对话框之dismiss和cancel和hide区别

    在我们看来两者效果都是一样的,其实看下源码就知道cancel肯定会去调dismiss的,如果调用的cancel的话就可以监听DialogInterface.OnCancelListener. /** ...

  2. ffmpeg 中 swscale 的用法

    http://www.guguclock.com/2009/12/ffmpeg-swscale.html 如果想將某個PixelFormat轉換至另一個PixelFormat,例如,將YUV420P轉 ...

  3. [转]YII2 常用数据库操作

    1.对象操作: //1.简单查询 $admin=Admin::model()->findAll($condition,$params); $admin=Admin::model()->fi ...

  4. hybrid开发设计

    hybrid方案背景 大部分业务都是在不停改变的,我们希望native不发布新版本就可以让线上用户使用新功能.我们要实现这样的方式,采用h5来实现就可以满足这一要求,准确说是native里提供一个装载 ...

  5. 【转载】linux内核启动android文件系统过程分析

    主要介绍linux 内核启动过程以及挂载android 根文件系统的过程,以及介绍android 源代码中文件系统部分的浅析. 主要源代码目录介绍Makefile (全局的Makefile)bioni ...

  6. 有了Hadoop MapReduce, 为什么还要Spark?

    a. 由于MapReduce的shuffle过程需写磁盘,比较影响性能:而Spark利用RDD技术,计算在内存中进行. b. MapReduce计算框架(API)比较局限, 而Spark则是具备灵活性 ...

  7. Android应用安全之Content Provider安全

    android平台提供了Content Provider,将一个应用程序的指定数据集提供给其它应用程序.这些数据可以存储在文件系统.SQLite数据库中,或以任何其它合理的方式存储.其他应用可以通过C ...

  8. Apk去签名校验详解

    某些apk为了防止重打包,使用了签名校验.所以在破解的时候我们需要破解签名校验.在定位签名校验位置时常用的关键词有sign,signature,checkSign,signCheck,getPacka ...

  9. WCF安全2-非对称加密

    概述: 数字签名和加密依赖于相应的加密算法 自变量:加密前的数据.密钥 因变量:加密后的数据 加密算法分类:根据加密和解密这两种步骤采用的密钥的是否相同进行分类 相同:对称加密 不相同:非对称加密 非 ...

  10. [Design Patterns] 4. Creation Pattern

    设计模式是一套被反复使用.多数人知晓的.经过分类编目的.代码设计经验的总结,使用设计模式的目的是提高代码的可重用性,让代码更容易被他人理解,并保证代码可靠性.它是代码编制真正实现工程化. 四个关键元素 ...