MVC Filters
MVC Filters
demo
Controll:AuthFiltersController
action Welcome添加了系统自带的过滤器Authorize
public class AuthFiltersController : Controller { // // GET: /AuthFilters/ public ActionResult Index() { return View(); } [Authorize] public ActionResult Welcome() { return View(); } }
Controll:AccountController 用户登录和注销
webconfig配置中的:
<authentication mode="Forms"> <forms loginUrl="~/Account/Login" timeout="2880" /> </authentication>
public class AccountController : Controller { // // GET: /Account/ public ActionResult Index() { return View(); } public ActionResult Login() { filter.Models.LogOnViewModel mode = new Models.LogOnViewModel(); return View(); } [HttpPost] public ActionResult Login(filter.Models.LogOnViewModel mode) { if (mode.UserName.Trim() == mode.Password.Trim()) //伪代码,只要输入的用户名和密码一样就过 { if (mode.RememberMe) FormsAuthentication.SetAuthCookie(mode.UserName, true); //2880分钟有效期的cookie else FormsAuthentication.SetAuthCookie(mode.UserName, false); //会话cookie return RedirectToAction("Welcome", "AuthFilters"); } else return View(mode); } public ActionResult Logout() { Session.Abandon(); FormsAuthentication.SignOut(); return RedirectToAction("Login", "Account"); } }
welcome页面:
@{ ViewBag.Title = "Welcome"; } <h2>Welcome</h2> @{ if (Request.IsAuthenticated) { <text>Hello,</text> @User.Identity.Name <span> @Html.ActionLink("注销", "Logout", "Account")</span> } } <p />
login页面:
@model filter.Models.LogOnViewModel @{ ViewBag.Title = "Login"; } <h2>Login</h2> @using (Html.BeginForm()) { @Html.AntiForgeryToken() @Html.ValidationSummary(true) <fieldset> <legend>LogOnViewModel</legend> <div class="editor-label"> 用户名 </div> <div class="editor-field"> @Html.EditorFor(model => model.UserName) </div> <div class="editor-label"> 密码 </div> <div class="editor-field"> @Html.EditorFor(model => model.Password) </div> <div class="editor-label"> 记住我 </div> <div class="editor-field"> @Html.CheckBoxFor(model => model.RememberMe) </div> <p><input type="submit" value="登录" /></p> </fieldset> } <div> @Html.ActionLink("Back to List", "Index") </div> @section Scripts { @Scripts.Render("~/bundles/jqueryval") }
逻辑:访问Authfilters/Welcome 页面,如果没有登录在跳转到Account/Login页面。
****** FormsAuthentication.SetAuthCookie(mode.UserName, true) 系统自带写入cookie
MVC几个默认的过滤器
1.授权过滤器
授权筛选器用于实现IAuthorizationFilter接口和做出关于是否执行操作方法(如执行身份验证或验证请求的属性)的安全决策。 AuthorizeAttribute类和RequireHttpsAttribute类是授权筛选器的示例。
授权筛选器在任何其他筛选器之前运行。
AuthorizeAttribute类:
namespace System.Web.Mvc { // 摘要: // 表示一个特性,该特性用于限制调用方对操作方法的访问。 [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = true)] public class AuthorizeAttribute : FilterAttribute, IAuthorizationFilter { // 摘要: // 初始化 System.Web.Mvc.AuthorizeAttribute 类的新实例。 public AuthorizeAttribute(); // 摘要: // 获取或设置用户角色。 // // 返回结果: // 用户角色。 public string Roles { get; set; } // // 摘要: // 获取此特性的唯一标识符。 // // 返回结果: // 此特性的唯一标识符。 public override object TypeId { get; } // // 摘要: // 获取或设置授权用户。 // // 返回结果: // 授权用户。 public string Users { get; set; } // 摘要: // 重写时,提供一个入口点用于进行自定义授权检查。 // // 参数: // httpContext: // HTTP 上下文,它封装有关单个 HTTP 请求的所有 HTTP 特定的信息。 // // 返回结果: // 如果用户已经过授权,则为 true;否则为 false。 // // 异常: // System.ArgumentNullException: // httpContext 参数为 null。 protected virtual bool AuthorizeCore(HttpContextBase httpContext); // // 摘要: // 处理未能授权的 HTTP 请求。 // // 参数: // filterContext: // 封装有关使用 System.Web.Mvc.AuthorizeAttribute 的信息。filterContext 对象包括控制器、HTTP 上下文、请求上下文、操作结果和路由数据。 protected virtual void HandleUnauthorizedRequest(AuthorizationContext filterContext); // // 摘要: // 在过程请求授权时调用。 // // 参数: // filterContext: // 筛选器上下文,它封装有关使用 System.Web.Mvc.AuthorizeAttribute 的信息。 // // 异常: // System.ArgumentNullException: // filterContext 参数为 null。 public virtual void OnAuthorization(AuthorizationContext filterContext); // // 摘要: // 在缓存模块请求授权时调用。 // // 参数: // httpContext: // HTTP 上下文,它封装有关单个 HTTP 请求的所有 HTTP 特定的信息。 // // 返回结果: // 对验证状态的引用。 // // 异常: // System.ArgumentNullException: // httpContext 参数为 null。 protected virtual HttpValidationStatus OnCacheAuthorization(HttpContextBase httpContext); } }
要实现自定义的验证只需重写下OnAuthorization和AuthorizeCore方法。
Demo
SampleData数据实体类 以及相关的User类,Role类,RoleWithControllerAction类
public class SampleData { public static List<User> users; public static List<Role> roles; public static List<RoleWithControllerAction> roleWithControllerAndAction; static SampleData() { // 初始化用户 users = new List<User>(){ new User(){ Id=1, UserName="wangjie", RoleId=1}, new User(){ Id=2, UserName ="senior1", RoleId=2}, new User(){ Id=3, UserName ="senior2", RoleId=2}, new User(){ Id=5, UserName="junior1", RoleId=3}, new User(){ Id=6, UserName="junior2", RoleId=3}, new User(){ Id=6, UserName="junior3", RoleId=3} }; // 初始化角色 roles = new List<Role>() { new Role() { Id=1, RoleName="管理员", Description="管理员角色"}, new Role() { Id=2, RoleName="高级会员", Description="高级会员角色"}, new Role() { Id=3, RoleName="初级会员", Description="初级会员角色"} }; // 初始化角色控制器和Action对应类 roleWithControllerAndAction = new List<RoleWithControllerAction>() { new RoleWithControllerAction(){ Id=1, ControllerName="AuthFilters", ActionName="AdminUser", RoleIds="1"}, new RoleWithControllerAction(){ Id=2, ControllerName="AuthFilters", ActionName="SeniorUser", RoleIds="1,2"}, new RoleWithControllerAction(){ Id=3, ControllerName="AuthFilters", ActionName="JuniorUser", RoleIds="1,2,3"}, new RoleWithControllerAction(){ Id=4, ControllerName="ActionFilters", ActionName="Index", RoleIds="2,3"} }; } }
public class User { public int Id { get; set; } public string UserName { get; set; } public int RoleId { get; set; } }
public class Role { public int Id { get; set; } public string RoleName { get; set; } public string Description { get; set; } }
public class RoleWithControllerAction { public int Id { get; set; } public string ControllerName { get; set; } public string ActionName { get; set; } public string RoleIds { get; set; } }
自定义UserAuthorize类继承于AuthorizeAttribute,来实现用户权限操作,重写了OnAuthorization和AuthorizeCore
public class UserAuthorize : AuthorizeAttribute { //定义一个授权失败时呈现的视图 public string AuthorizeFailView { get; set; } /// <summary> /// 查找请求报文中的controller和action,对应数据源中的rolesId /// </summary> /// <param name="filterContext"></param> public override void OnAuthorization(AuthorizationContext filterContext) { //获取当前请求的controller和action string controllerName = filterContext.RouteData.Values["controller"].ToString(); string actionName = filterContext.RouteData.Values["action"].ToString(); //根据当前请求的cotroller和action 去查找数据源中的对应的角色,并赋值给父类的Roles; var currentRoles = filter.DataBase.SampleData.roleWithControllerAndAction.Find(u => u.ControllerName == controllerName && u.ActionName == actionName); this.Roles = currentRoles.RoleIds; base.OnAuthorization(filterContext); } /// <summary> /// /// </summary> /// <param name="httpContext"></param> /// <returns></returns> protected override bool AuthorizeCore(HttpContextBase httpContext) { if (httpContext.User.Identity.IsAuthenticated)//判断用户是否已经登录 { var userName = httpContext.User.Identity.Name;//获取当前报文中的用户名 var currenUserModel = filter.DataBase.SampleData.users.Find(u => u.UserName == userName);//查找当前用户是否存在 if (currenUserModel != null) { foreach (var roleId in this.Roles.Split(',')) { if (roleId == currenUserModel.RoleId.ToString()) { return true; } } return false; } else { return false; } } else { return false; } //return base.AuthorizeCore(httpContext); } /// <summary> /// 处理授权失败的HTTP请求 /// </summary> /// <param name="filterContext"></param> protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext) { if (this.AuthorizeFailView == null) this.AuthorizeFailView = "Error"; filterContext.Result = new ViewResult() { ViewName = AuthorizeFailView }; //throw new Exception("权限不够,出错了"); //filterContext.HttpContext.Response.Redirect("/Account/Login", true);//强制跳转当前请求 } }
控制器中的action加上自定义的过滤器
public class AuthFiltersController : Controller { // // GET: /AuthFilters/ public ActionResult Index() { return View(); } [Authorize] public ActionResult Welcome() { return View(); } [UserAuthorize(AuthorizeFailView = "Error")] public ActionResult AdminUser() { return View(); } [UserAuthorize(AuthorizeFailView = "Error")] public ActionResult SeniorUser() { return View(); } [UserAuthorize(AuthorizeFailView = "Error")] public ActionResult JuniorUser() { return View(); } }
2.操作筛选器、结果筛选器
操作筛选器用于实现IActionFilter接口以及包装操作方法执行。IActionFilter接口声明两个方法:OnActionExecuting和OnActionExecuted。OnActionExecuting在操作方法之前运行。OnActionExecuted在操作方法之后运行,可以执行其他处理,如向操作方法提供额外数据、检查返回值或取消执行操作方法。
结果筛选器用于实现IResultFilter接口以及包装ActionResult对象的执行。IResultFilter接口声明两个方法OnResultExecuting和OnResultExecuted。OnResultExecuting在执行ActionResult对象之前运行。OnResultExecuted在结果之后运行,可以对结果执行其他处理,如修改 HTTP 响应。OutputCacheAttribute 类是结果筛选器的一个示例。
public virtual void OnActionExecuted(ActionExecutedContext filterContext); public virtual void OnActionExecuting(ActionExecutingContext filterContext); public virtual void OnResultExecuted(ResultExecutedContext filterContext); public virtual void OnResultExecuting(ResultExecutingContext filterContext);
根据方法的名字就知道4个方法执行的顺序了:
OnActionExecuting是Action执行前的操作、OnActionExecuted则是Action执行后的操作、OnResultExecuting是解析ActionResult前执行、OnResultExecuted是解析ActionResult后执行。
即:Action执行前:OnActionExecuting方法先执行→Action执行 →OnActionExecuted方法执行→OnResultExecuting方法执行→返回的ActionRsult中的 executeResult方法执行→OnResultExecuted执行