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:窗体身份验证及角色权限管理示例的更多相关文章

  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. 关于STM8空间不足的解决方法

    STM8虽然功能齐全,但是空间不足也是经常出来的情况.要么.text overflow,要么.bss overflow,让人头疼.这里把一些优化方案列出来,让空间得到充分利用: 1.在Project ...

  2. Query Object--查询对象模式(下)

    回顾 上一篇对模式进行了介绍,并基于ADO.NET进行了实现,虽然现在ORM框架越来越流行,但是很多中小型的公司仍然是使用ADO.NET来进行数据库操作的,随着项目的需求不断增加,业务不断变化,ADO ...

  3. Android studio动态调试smali

    前面介绍了使用IDA动态调试smali,这种方法设置简单,不用重打包,用起来方便,但是如果变量类型设置错误则会马上退出调试,这是让人不爽的地方,而使用Android studio则不会.   0x01 ...

  4. `cocos2dx非完整` 添加xxtea加密模块

    在上一篇文章中,我已经开始着手写自己的模块,也就是fw部分.其中上一篇文章中完成的是lua部分的配置解析部分,涉及一点点平台方面的封装.这一片文章我来说明一下我是如何处理cocos2dx资源加密的.首 ...

  5. 【原创】C#搭建足球赛事资料库与预测平台(3) 基础数据表设计

            本博客所有文章分类的总目录:http://www.cnblogs.com/asxinyu/p/4288836.html 开源C#彩票数据资料库系列文章总目录:http://www.cn ...

  6. Device.js – 快速检测平台、操作系统和方向信息

    在 Web 项目中,有时候我们需要根据程序运行的环境采取特定操作.Device.js 是一个很小的 JavaScript 库,它简化了编写和平台,操作系统或浏览器相关的条件 CSS 或 JavaScr ...

  7. 将excel导入mysql(使用navicat)

    excel: 注: 1.mysql里建立一张跟excel一样的表结构的表(包含id) 2.excel最好没有任何格式,只是纯值,不然会出现导入不了的错误 ----------------------- ...

  8. 新开博客 http://wylhyz.github.io/

    刚刚使用hexo在github pages上建立了静态博客,地址 http://wylhyz.github.io/

  9. Android上的事件流操作数据库

    最近在浏览某篇有关事件流的文章时,里面提到了数据的流处理,兴趣来了,就想看看能否在Android端实现一个. 根据文章的介绍,将每次数据的变更事件,像是插入,删除或者更新等,记为一个不可变的事件,让数 ...

  10. UWP开发入门(十二)——神器Live Visual Tree

    很久以前,我们就有Snoop这样的工具实时修改.查看正在运行的WPF程序,那时候调个样式,修改个模板,相当滋润.随着历史的车轮陷进WP的泥潭中,无论WP7的Silverlight还是WP8.1的run ...