MVC自带的ActionFilter

在Asp.Net WebForm的中要做到身份认证微软为我们提供了三种方式,其中最常用的就是我们的Form认证,需要配置相应的信息。例如下面的配置信息:

<authentication mode="Forms">
<forms loginUrl="Login.aspx" defaultUrl="Default.aspx" protection="All" />
</authentication>
<authorization>
<deny users="?"/>
<allow users="*"/>
</authorization>

说明我们登录页面是Login.aspx,登录成功后的默认页面是Default.aspx,而我们用户信息采用验证和加密两种方式。而且最重要的 是我们要写好授权方式(下面的授权一定要写否则只说明使用Forms认证然后设置相关属性是没有用的),拒绝所有匿名用户,只有登录用户可以正常访问。这 样之后我们设置点击登录按钮将用户名写进cookie(也就是执行FormsAuthentication.SetAuthCookie(name, false);)就可以了。

在Asp.Net MVC中我们同样可以使用Forms认证,但是如果你按照WebForm中的做法去做就不行了。例如你这样配置信息:

<authentication mode="Forms">
<forms loginUrl="~/Account/Login" defaultUrl="~/Home/Index" protection="All"/>
</authentication>
<authorization>
<deny users="?"/>
<allow users="*"/>
</authorization>

你在Login.aspx中设置登录来触发AccountController中的Logon来登录,其中Logon代码:

public ActionResult Logon(string name,string password)
{
if (name == "jianxin160" && password == "160796")
{
FormsAuthentication.SetAuthCookie(name, false);
return Redirect("~/Home/Index");
}
else
{
return Redirect("/");
}
}

这样的操作之后你会发现你的Logon是不会执行的。原因是什么呢?怎么同样的设置为什么到了MVC中就不行了?原因就是二者机制不同,因为你设置的授权方式让Logon无法访问了。那么我们怎么来做呢?

其实在Asp.Net MVC中我们有更好的方式来做这一切,我们不需要授权方式,也就是说我们的配置信息像这样:

<authentication mode="Forms">
<forms loginUrl="~/Account/Login" defaultUrl="~/Home/Index" protection="All"/>
</authentication>

不需要说明匿名用户不能登录等。当然了,你会发现仅仅就这样做肯定不行的我们还要换一种方式告诉系统哪些是需要登录才能访问的。你或许 想,o(︶︿︶)o 唉,那太麻烦了吧。其实不是这样的,很简单,我们只需要在需要认证的Action上标记[Authorize]就可以了。例如我在Home文件夹中有两个 页面Index和Home,我现在想让Index经过认证才能访问,而Home不需要,那么只需要给Index这个Action标记 [Authorize],也就是:

[Authorize]
public ActionResult Index()
{
return View();
} public ActionResult Home()
{
return View();
}

这样Index就必须登录之后才能访问,而Home是不需要登录的。如果你需要进行角色授权那么您就可以在标记Authorize的时候指明角色 (例如[Authorize(Role=Administrators)] ),不过您这是就必须使用微软给我们提供的Membership机制了,因为您的Role不可能是平白无故有的,而是存在于对应的数据库中的,这个我在另 一篇博客中提到过就不多说了。

自定义ActionFilter

有时候这样的认证或许您还不能够满足,或者说您觉得不够灵活,那么也没有关系,Asp.Net MVC是允许您自定义ActionFilter的。例如我现在自定义身份认证:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Security; namespace FormFormsAuthenticationMvc
{
public class RequiresAuthenticationAttribute:ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
if (!filterContext.HttpContext.User.Identity.IsAuthenticated)
{
string returnUrl = filterContext.HttpContext.Request.Url.AbsolutePath;
string redirectUrl = string.Format("?ReturnUrl={0}", returnUrl);
string loginUrl = FormsAuthentication.LoginUrl + redirectUrl;
filterContext.HttpContext.Response.Redirect(loginUrl, true);
}
}
}
}

如果需要进行用户管理,我再定义角色相关的Filter:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Security; namespace MvcApplication1.MyClass
{
public class RequiresRoleAttribute:ActionFilterAttribute
{
public string Role { get; set; } public override void OnActionExecuting(ActionExecutingContext filterContext)
{
if (!string.IsNullOrEmpty(Role))
{
if (!filterContext.HttpContext.User.Identity.IsAuthenticated)
{
string returnUrl = filterContext.HttpContext.Request.Url.AbsolutePath;
string redirectUrl = string.Format("?ReturnUrl={0}", returnUrl);
string loginUrl = FormsAuthentication.LoginUrl + redirectUrl;
filterContext.HttpContext.Response.Redirect(loginUrl, true);
}
else
{
bool isAuthenticated = filterContext.HttpContext.User.IsInRole(Role);
if (!isAuthenticated)
{
throw new UnauthorizedAccessException("You have no right to view the page!");
}
}
}
else
{
throw new InvalidOperationException("No Role Specified!");
}
}
}
}

其实您会发现上面两个Attribute其实MVC自带的Authorized已经解决了,这里主要告诉大家如果有需要您是可以扩展的。

好了,今天就到这里吧!源代码下载:FormFormsAuthenticationMvc

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 事件的处理函数。

代码下载:Mvc-FormsAuthentication-RolesAuthorization-1.rar (243KB)

方式二

此方式将用户的角色保存至用户 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);
}
}
//...
}

代码下载:Mvc-FormsAuthentication-RolesAuthorization-2.rar (244KB)

三、角色权限

使用任一种方式后,我们就可以在 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) { /**/}
/**/
}

MVC身份验证及权限管理的更多相关文章

  1. MVC身份验证及权限管理(转载)

    from https://www.cnblogs.com/asks/p/4372783.html MVC自带的ActionFilter 在Asp.Net WebForm的中要做到身份认证微软为我们提供 ...

  2. (转) MVC身份验证及权限管理-2

    转自:http://www.cnblogs.com/ldp615/archive/2010/10/27/asp-net-mvc-forms-authentication-roles-authoriza ...

  3. (转) MVC身份验证及权限管理-1

    转自:http://blog.csdn.net/kenshincui/article/details/5559508 MVC自带的ActionFilter 在Asp.Net WebForm的中要做到身 ...

  4. mvc5+ef6+Bootstrap 项目心得--身份验证和权限管理

    1.mvc5+ef6+Bootstrap 项目心得--创立之初 2.mvc5+ef6+Bootstrap 项目心得--身份验证和权限管理 3.mvc5+ef6+Bootstrap 项目心得--WebG ...

  5. [转]mvc5+ef6+Bootstrap 项目心得--身份验证和权限管理

    本文转自:http://www.cnblogs.com/shootingstar/p/5629668.html 1.mvc5+ef6+Bootstrap 项目心得--创立之初 2.mvc5+ef6+B ...

  6. MVC自定义AuthorizeAttribute实现权限管理

    [转]MVC自定义AuthorizeAttribute实现权限管理 原文载自:小飞的DD http://www.cnblogs.com/feiDD/articles/2844447.html 网站的权 ...

  7. Asp.Net MVC 身份验证-Forms

    Asp.Net MVC 身份验证-Forms 在MVC中对于需要登录才可以访问的页面,只需要在对应的Controller或Action上添加特性[Authorize]就可以限制非登录用户访问该页面.那 ...

  8. [转]Asp.Net大型项目实践(11)-基于MVC Action粒度的权限管理【续】【源码在这里】(在线demo,全部源码)

    本文转自:http://www.cnblogs.com/legendxian/archive/2010/01/25/1655551.html 接上篇Asp.Net大型项目实践(10)-基于MVC Ac ...

  9. MVC身份验证.MVC过滤器.MVC6关键字Task,Async.前端模拟表单验证,提交.自定义匿名集合.Edge导出到Excel.BootstrapTree树状菜单的全选和反选.bootstrap可搜索可多选可全选下拉框

    1.MVC身份验证. 有两种方式.一个是传统的所有控制器继承自定义Control,然后再里面用MVC的过滤器拦截.所以每次网站的后台被访问时.就会先走入拦截器.进行前端和后端的验证 一个是利用(MVC ...

随机推荐

  1. 某返利网站admin目录index.php文件混淆加密算法分析

    ---恢复内容开始--- 文件已经加密,可以在此下载:index.php 文件内容打开大概如此: 简单字符替换之后,发现字符串用base64_decode仍无法解码. 找到一个解码网站:找源码 解码后 ...

  2. Ubuntu 14.04 没有system settings的解决方法

    在我的Dell Latitude 3330上, 新装的Ubuntu 14.04一切正常,就是没有system settings程序, 以下的命令能够解决: sudo apt-get install u ...

  3. Cubieboard 开箱和入门 | Name5566 分类: cubieboard 2014-11-08 17:27 251人阅读 评论(0) 收藏

    Cubieboard 开箱和入门 2014 年 01 月 29 日 by name5566 Categories: Computer Science, Cubieboard Hello Cubiebo ...

  4. [AngularJS + Unit Testing] Testing Directive's controller with bindToController, controllerAs and isolate scope

    <div> <h2>{{vm.userInfo.number}} - {{vm.userInfo.name}}</h2> </div> 'use str ...

  5. 解读dbcp自动重连那些事---转载

    http://agapple.iteye.com/blog/791943 可以后另一篇做对比:http://agapple.iteye.com/blog/772507 同样的内容,不同的描述方式,不一 ...

  6. 亲测apache

    http://www.cnblogs.com/bluewelkin/p/3805107.html 里面是纠正了原文的一些小错误,即可正常安装  1.su 命令 2.安装apr-1.3.5.tar.gz ...

  7. mac 下svn降级

    mac 手欠 homebrew 安装完成后  brew install  svn   svn版本更新至1.8.11 公司svn 不支持1.8  需要降级 搜索很多资料 写的比较麻烦 总结出来是先卸载再 ...

  8. 《3D数学基础:图形与游戏开发》勘误

    最近读这本书,读到四元素的乘法时,自己推导了一下公式,然后懵了,多方查阅,确定是书籍中的笔误(我读的是中文翻译版): 具体在Page147: 上图所示,在第二处明显与第一处的公式不一样. 在维基百科上 ...

  9. 论前端css初始化的重要性

    新手,求喷,刚刚知道每个浏览器都有对 标签的初始化,就造成我们网站开发者开发的web程序,会在不同的网站上有不同的样式风格,这给用户带来了很不好的体验,这也是浏览器本身的原因造成的,这时候,我们不可能 ...

  10. Unity3D GUI学习

    Unity3D内置有GUI, 首先,使用GUI实现一个按钮,并且点击实现触发, void OnGUI() { //GUI.Button (new Rect (10,10,50,50), "n ...