ASP.NET Core MVC 筛选器 过滤器

ASP.NET Core 中的筛选器  
ASP.NET Core 取消和设置短路  
ASP.NET MVC 4 自定义操作筛选器【旧版本 - MVC3 和 MVC4】

了解操作筛选器 (C#)【旧版本 - MVC1 和 MVC2】
Filters in ASP.NET Core sample  

MVC 过滤器 消息拦截

.NET Core OAuth IdentityServer4 Token 

身份验证和 ASP.NET Web API 中的授权 
Web API 异常筛选器
Web API 身份验证筛选器  
实现 Web API 身份验证筛选器  
ASP.NET Web API 安全筛选器  
ASP.NET Core 的客户端 IP 安全安全(IP安全列表) 方式方式(中间件AdminSafeListMiddleware,筛选器ClientIpCheckFilter)
验证失败错误响应 模型验证失败
文档目录  
.NET 文档  
ASP.NET 文档  


1、筛选器:
   授权筛选器:从而安全决定是否要执行的操作方法,如执行身份验证或验证请求的属性。
   操作筛选器:用于包装操作方法执行。 此筛选器可以执行其他处理,如提供给操作方法的额外数据、 检查返回值,或取消执行的操作方法
   结果筛选器:用于包装的 ActionResult 对象执行。 此筛选器可以执行其他处理的结果,如修改 HTTP 响应。
   异常筛选器:如果没有在操作方法中,使用授权筛选器开始和结束与结果执行的某个位置引发未处理的异常,则执行。 异常筛选器可用于任务,例如日志记录或显示错误页。

   身份验证筛选器 – IAuthenticationFilter
   授权筛选器 – 实现IAuthorizationFilter属性。(或AuthorizeAttribute)
   操作筛选器 – 实现IActionFilter属性。(或ActionFilterAttribute)
   结果筛选器 – 实现IResultFilter属性。(或ActionFilterAttribute)
   异常筛选器 – 实现IExceptionFilter属性。(或HandleErrorAttribute)

2、筛选器

   ActionFilterAttribute:是所有属性筛选器的基类【ActionFilterAttribute Class】
   OnActionExecuting(ActionExecutingContext filterContext) - 在执行控制器操作“之前”,将调用此方法
   OnActionExecuted(ActionExecutedContext filterContext) – 在执行控制器操作“后”,将调用此方法。
   OnResultExecuting(ResultExecutingContext filterContext): – 调用此方法在执行控制器操作结果“之前”
   OnResultExecuted(ResultExecutedContext filterContext):   – 调用此方法“后”在执行控制器操作结果。

   AuthorizeAttribute:指定对控制器或操作方法的访问仅限于满足授权要求的用户【AuthorizeAttribute Class】
   AuthorizeCore(HttpContextBase) - 当被重写时,为自定义授权检查提供入口点.
   HandleUnauthorizedRequest(AuthorizationContext) - 处理授权失败的HTTP请求.
   OnAuthorization(AuthorizationContext) - 当进程请求授权时调用.
   OnCacheAuthorization(HttpContextBase) - 当缓存模块请求授权时调用.

   HandleErrorAttribute:表示用于处理操作方法引发的异常的属性【HandleErrorAttribute Class】
   OnException(ExceptionContext) - 发生异常时调用.

3、授权筛选器 - AuthorizeAttribute(示例)

using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;

namespace HappyShop.Web.Filters
{
    public class CustomerAuthorizeAttribute : AuthorizeAttribute
    {
        public new string[] Roles { get; set; }
        private HttpRequestBase _request;

        protected override bool AuthorizeCore(HttpContextBase httpContext)
        {
            _request = httpContext.Request;
            if (httpContext == null && httpContext.Session == null)
                throw new ArgumentNullException("HttpContext");
            
            if (!httpContext.User.Identity.IsAuthenticated)
                return false;

            if (!httpContext.Request.Cookies.AllKeys.Contains("CookieKey"))
                return false;

            var cookie = httpContext.Request.Cookies["CookieKey"];
            if (string.IsNullOrEmpty(cookie?.Value))
            {
                return false;
            }

            if (Roles == null)
            {
                return true;
            }
            if (Roles.Length == 0)
            {
                return true;
            }
            if (Roles.Any(httpContext.User.IsInRole))
            {
                return true;
            }
            return false;
        }

        public override void OnAuthorization(AuthorizationContext filterContext)
        {
            var httpContext = filterContext.HttpContext;
            _request = httpContext.Request;

            string controllerName = filterContext.ActionDescriptor.ControllerDescriptor.ControllerName;
            string actionName = filterContext.ActionDescriptor.ActionName;
            string roles = "1,2,3";
            if (!string.IsNullOrWhiteSpace(roles))
            {
                this.Roles = roles.Split(new string[] { "," }, StringSplitOptions.RemoveEmptyEntries);
            }
            base.OnAuthorization(filterContext);
        }
    }
}

4、操作筛选器 - ActionFilterAttribute(示例)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;

namespace HappyShop.Web.Filters
{
    public class LogActionFilter : ActionFilterAttribute
    {
        public override void OnActionExecuting(ActionExecutingContext filterContext)
        {
            var controller = filterContext.ActionDescriptor.ControllerDescriptor.ControllerName;
            var action = filterContext.ActionDescriptor.ActionName;
            Log("OnActionExecuting", filterContext.RouteData);
        }

        public override void OnActionExecuted(ActionExecutedContext filterContext)
        {
            Log("OnActionExecuted", filterContext.RouteData);
        }

        public override void OnResultExecuting(ResultExecutingContext filterContext)
        {
            Log("OnResultExecuting", filterContext.RouteData);
        }

        public override void OnResultExecuted(ResultExecutedContext filterContext)
        {
            Log("OnResultExecuted", filterContext.RouteData);
        }

        private void Log(string methodName, RouteData routeData)
        {
            var controllerName = routeData.Values["controller"];
            var actionName = routeData.Values["action"];
            var message = String.Format("{0} controller:{1} action:{2}", methodName, controllerName, actionName);
            Console.WriteLine(message, "Action Filter Log");
        }

    }
}

5、异常筛选器 - HandleErrorAttribute(示例)

using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;

namespace HappyShop.Web.Filters
{
    public class CustomerExceptionAttribute : HandleErrorAttribute
    {
        public override void OnException(ExceptionContext filterContext)
        {
            base.OnException(filterContext);

            filterContext.ExceptionHandled = true;

            var url = filterContext.RequestContext.HttpContext.Request.Url.AbsolutePath;

            Exception ex = filterContext.Exception;
            WriteLog(ex);

            ///方式一
            filterContext.Result = new RedirectResult("~/Shared/Error");

            ///方式二
            filterContext.Result = new ContentResult()
            {
                Content = JsonConvert.SerializeObject(new
                {
                    Success = false,
                    Msg = $"--url:{DateTime.Now:HH:mm:ss.fff};服务器内部错误"
                })
            };
        }

        private void WriteLog(Exception exception)
        {
            //...
        }
    }
}

实现 Web API 身份验证筛选器
在 Web API 中,身份验证筛选器实现 System.Web.Http.Filters.IAuthenticationFilter 接口。 继承自System.Attribute,作为属性应用。
IAuthenticationFilter 接口有两个方法:
    AuthenticateAsync请求进行身份验证通过验证凭据在请求中,如果存在。
    ChallengeAsync必要到 HTTP 响应中,添加身份验证质询。
*
*
*
----------------------------ASP.NET Core 筛选器----------------------------
操作筛选器    ASP.NET Core 3.0 操作筛选器
实现 IActionFilterIAsyncActionFilter 接口。
若要设置短路,可将 Microsoft.AspNetCore.Mvc.Filters.ActionExecutingContext.Result 分配到某个结果实例,并且不调用 next (ActionExecutionDelegate)。
该框架提供一个可子类化的抽象 ActionFilterAttribute
OnActionExecuting 操作筛选器可用于:
   验证模型状态。
   如果状态无效,则返回错误。

public class ValidateModelAttribute : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext context)
    {
        if (!context.ModelState.IsValid)
        {
            context.Result = new BadRequestObjectResult(context.ModelState);
        }

        var request = context.HttpContext.Request;
        var headers = request.Headers;
        var origins = Configuration["AppSettings:Origins"].Split(',');
        var origin = context.HttpContext.Request.Headers["Origin"].FirstOrDefault();
        var host = context.HttpContext.Request.Headers["Host"].FirstOrDefault();
        var cookie = context.HttpContext.Request.Headers["Cookie"].FirstOrDefault();
        string referer = context.HttpContext.Request.Headers["Referer"].ToString();
        var list = referer.Split("/").Where(x => !string.IsNullOrEmpty(x) && !x.Contains("v") && !x.Contains("api")).ToArray();

        if (!origins.Any(x => x == origin) && !origins.Any(x => x == host))
        {
            context.Result = new JsonResult(new { code = "401", msg = "未经授权的非法请求"
        });
            return;
        }
        if (list != null && list.Length > 0)
        {
            if (!origins.Any(x => x == list[1]))
            {
                context.Result = new JsonResult(new { code = "401", msg = "未经授权的非法请求" });
                return;
            }
        }
    }

    public override void OnActionExecuted(ActionExecutedContext context)
    {
        var result = context.Result;
        // Do something with Result.
        if (context.Canceled == true)
        {
            // Action execution was short-circuited by another filter.
        }

        if(context.Exception != null)
        {
            // Exception thrown by action or action filter.
            // Set to null to handle the exception.
            context.Exception = null;
        }
        base.OnActionExecuted(context);
    }
}

获取 Header 参数

public class ValidateModelAttribute : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext context)
    {
        var headers = context.HttpContext.Request.Headers;
        var userId = headers["use_id"].FirstOrDefault().ToLower();

        var isDefined = false;
        var controllerActionDescriptor = context.ActionDescriptor as ControllerActionDescriptor;
        if (controllerActionDescriptor != null)
        {
            isDefined = controllerActionDescriptor.MethodInfo.GetCustomAttributes(inherit: true)
              .Any(a => a.GetType().Equals(typeof(NoPermissionAttribute)));
        }
        if (isDefined) return;
    }
}

ASP.NET Core 3.0 取消和设置短路  
通过设置提供给筛选器方法的 ResourceExecutingContext 参数上的 Result 属性,可以使筛选器管道短路。 例如,以下资源筛选器将阻止执行管道的其余阶段:

public class ShortCircuitingResourceFilterAttribute : Attribute, IResourceFilter
{
    public void OnResourceExecuting(ResourceExecutingContext context)
    {
        context.Result = new ContentResult()
        {
            Content = "Resource unavailable - header not set."
        };
    }
}

以下操作筛选器设置短路,阻止执行管道其余阶段:

public class PermissionAttribute : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext context)
    {
        if (string.IsNullOrWhiteSpace(context.HttpContext.Request.Query["LoginInfo"].ToString()))
        {
            context.Result = new JsonResult(new { Code = EnumCode.UnAuthorized, Message = "未经授权" });
        }
        base.OnActionExecuting(context);
    }
}

7、AuthorizeFilter 过滤器判断是否添加了[Authorize]特性,通常添加在 资源服务器 的过滤器中

using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc.Authorization;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.AspNetCore.Mvc;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Security.Claims;
using Microsoft.AspNetCore.Authorization.Infrastructure;

namespace Test.WebAPI
{
    public class TestAuthorizeAttribute : AuthorizeFilter
    {
        private static AuthorizationPolicy _policy_ = new AuthorizationPolicy(
            new[] { new DenyAnonymousAuthorizationRequirement() },
            new string[] { });

        public TestAuthorizeAttribute () : base(_policy_) { }

        /// 
        ///  请求验证,当前验证部分不要抛出异常,ExceptionFilter不会处理
        /// 
        /// 请求内容信息
        public override async Task OnAuthorizationAsync(AuthorizationFilterContext context)
        {
            await base.OnAuthorizationAsync(context);

            if (!context.HttpContext.User.Identity.IsAuthenticated ||
                 context.Filters.Any(item => item is IAllowAnonymousFilter)) return;

            var request = context.HttpContext.Request;
            var headers = request.Headers;
            var deviceId = headers["device_id"].FirstOrDefault().ToLower();

            if (context.HttpContext.User.Identity.IsAuthenticated)
            {
                var claimIdentity = (ClaimsIdentity)context.HttpContext.User.Identity;
                Claim userClaim = claimIdentity.Claims.Where(x => x.Type.Contains("user_code")).FirstOrDefault();
                Claim userClaim = claimIdentity.Claims.Where(x => x.Type.Contains("device_id")).FirstOrDefault();

                if (userClaim.Value != deviceId)
                {
                    context.Result = new JsonResult(new { code = ((int)EnumCode.UnAuthorized).ToString(), msg = "未经授权的非法请求" });
                    return;
                }

                if (IsHaveAllow(context.Filters))
                {
                    return;
                }

                //解析url
                // {/ Home / Index}
                var originalUrl = context.HttpContext.Request.Path.Value;
                if (string.IsNullOrWhiteSpace(originalUrl))
                {
                    return;
                }

                var list = originalUrl.Split("/");
                var liit = originalUrl.Split("/").Where(x => !x.Contains("v") && !x.Contains("api")).ToArray();
                var controllerName = list[1].ToString().Trim();
                var actionName = list[2].ToString().Trim();
                if (list.Length <= 0 || url == "/")
                {
                    return;
                }

                //验证
                var flag = IsHavePower(controllerName, actionName);
                if (flag != 0)
                {
                    context.Result = new RedirectResult("/Home/Index");
                }
            }
            if (context.HttpContext.User.Identity.Name != "admin")
            {
                //未通过验证则跳转到无权限提示页
                RedirectToActionResult content = new RedirectToActionResult("NoAuth", "Exception", null);
                context.Result = content;
            }

            ///判断请求参数中是否存在某个特定值
            if (string.IsNullOrWhiteSpace(context.HttpContext.Request.Query["LoginInfo"].ToString()))
            {
                //context.Result = new JsonResult(new { code = ((int)EnumCode.UnAuthorized).ToString(), msg = "未经授权" });
            }
        }

        /// 
        /// 判断是否不需要权限
        /// 
        /// 
        /// 
        public static bool IsHaveAllow(IList filers)
        {
            for (int i = 0; i < filers.Count; i++)
            {
                if (filers[i] is IAllowAnonymousFilter)
                {
                    return true;
                }
            }
            return false;
        }

        public static int IsHavePower(string controllerName, string actionName)
        {
            return 0;
        }

    }

    public class AllowAnonymous : AuthorizeFilter, IAllowAnonymousFilter
    {

    }

    public class PermissionRequiredAttribute : ActionFilterAttribute
    {
        public override void OnActionExecuting(ActionExecutingContext filterContext)
        {
        }
    }


    public class PermissionHandler : IAuthorizationHandler
    {
        public Task HandleAsync(AuthorizationHandlerContext context)
        {
            var pendingRequirements = context.PendingRequirements.ToList();

            foreach (var requirement in pendingRequirements)
            {
            }

            //TODO: Use the following if targeting a version of
            //.NET Framework older than 4.6:
            //      return Task.FromResult(0);
            return Task.CompletedTask;
        }

        private bool IsOwner(ClaimsPrincipal user, object resource)
        {
            // Code omitted for brevity

            return true;
        }

        private bool IsSponsor(ClaimsPrincipal user, object resource)
        {
            // Code omitted for brevity

            return true;
        }
    }
}

*
*
*
*
*
*
*
*
*
示例
*
*
*
*
*
*
*
*

你可能感兴趣的:(.Net技术,.NET,Core,过滤器,Filter,Attribute)