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>
        &nbsp;&nbsp;
        @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执行

原文地址:https://www.cnblogs.com/youguess/p/13092496.html