在 .NET 中配置过滤器(Filter)涉及在 ASP.NET Core MVC 或 Web API 应用程序中使用过滤器来处理 HTTP 请求的前置和后置条件。过滤器可以在控制器执行前后以及操作执行前后执行。常见的过滤器类型包括认证过滤器、授权过滤器、资源过滤器、操作过滤器和异常过滤器。
1、认证过滤器
认证过滤器(Authentication Filter)在 ASP.NET Core 中负责对用户的身份进行验证,确保请求来自经过身份验证的用户。它是过滤器管道中的第一个步骤,用来判断请求的来源是否有效。通常,认证过滤器会检查请求中的身份凭证(例如令牌、Cookie 等),并基于此确定用户的身份。
认证过滤器的作用
认证过滤器的主要职责是:
- 验证用户身份:确定请求是否包含有效的身份凭证,如 JWT(JSON Web Token)、OAuth 令牌、API 密钥、Session Cookie 等。
- 为请求上下文添加用户信息:如果认证成功,认证过滤器将用户信息(如用户身份
ClaimsPrincipal
)添加到请求上下文(HttpContext.User
)中,这样后续的过滤器和控制器可以使用该信息。 - 拒绝未认证的请求:如果请求没有包含有效的身份凭证,认证过滤器可以阻止请求进入控制器,并直接返回未授权的响应(如 401 Unauthorized)。
认证过滤器与其他过滤器的关系
认证过滤器是过滤器管道中的第一个过滤器,它在授权过滤器(Authorization Filters)之前执行:
- 认证过滤器:检查用户是否经过身份验证。
- 授权过滤器:在身份验证成功的基础上,进一步检查用户是否有访问资源的权限。
举例来说,认证过滤器会确保用户已经登录,授权过滤器则会检查该用户是否具有访问某个资源的权限。
/// <summary>
/// 自定义权限过滤器
/// </summary>
public class CustomAuthorityFilter : Attribute, IAuthorizationFilter
{
/// <summary>
/// 通过依赖注入的方式传递数据
/// </summary>
public ISharedDataService sharedDataService;
public CustomAuthorityFilter(ISharedDataService sharedDataService)
{
this.sharedDataService = sharedDataService;
}
public void OnAuthorization(AuthorizationFilterContext context)
{
//假设简单的进行 API 密钥认证
var apiKey=context.HttpContext.Request.Headers["ApiKey"].FirstOrDefault();
if (apiKey==null||apiKey!= "valid-api-key")
{
//如果API密钥不正确,返回401
context.Result=new UnauthorizedResult();
}
//使用依赖注入的方式传递数据
sharedDataService.Data="这是我的数据";
//使用HttpContext.Items 给控制器传递数据
context.HttpContext.Items["MyData"]= "这是我的数据";
//使用ControllerContext.RouteData.Values给控制器传递数据
context.RouteData.Values["MyData"] = "这是我的数据";
}
}
为什么认证一般由中间件处理?
ASP.NET Core 中的认证通常通过中间件而不是过滤器来处理,因为认证涉及到整个应用的请求生命周期。例如,JWT 令牌或 Cookie 通常会在请求到达控制器之前就被解析,并将用户信息添加到 HttpContext.User
中。通过中间件实现,可以确保所有请求都经过身份验证,而不必依赖控制器或过滤器的存在。
2、授权过滤器
public class CustomAuthorizationFilter : IAuthorizationFilter
{
public void OnAuthorization(AuthorizationFilterContext context)
{
var user = context.HttpContext.User;
// 如果用户未认证,返回 401 未授权
if (!user.Identity.IsAuthenticated)
{
context.Result = new UnauthorizedResult();
return;
}
// 如果用户不具有某个特定声明,返回 403 禁止访问
if (!user.HasClaim(c => c.Type == "Permission" && c.Value == "CanAccess"))
{
context.Result = new ForbidResult();
}
}
}
3、资源过滤器
资源过滤器(Resource Filters)在 ASP.NET Core 中是用来在模型绑定之前或操作结果之后进行处理的过滤器。它们可以用来实现一些前置和后置处理逻辑,比如缓存处理、资源管理、以及请求数据的预处理等。
用途
资源过滤器通常用于以下几个方面:
- 缓存控制:在执行主要的操作逻辑之前,检查是否有缓存的结果可以直接返回,从而避免不必要的数据库查询或复杂计算。
- 资源的初始化和释放:确保在请求处理的前后分配和释放必要的资源,例如数据库连接、文件句柄等。
- 请求数据的预处理:在模型绑定之前对请求数据进行预处理或验证。
- 响应的后处理:在发送响应到客户端之前进行最后的数据修改或格式化。
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
namespace AopDemo.Filter
{
/// <summary>
/// 定义一个自定义的资源过滤器
/// </summary>
public class CustomResourceFilter : Attribute, IResourceFilter
{
//定义一个缓存字典
private static readonly Dictionary<string, object> Cache = new Dictionary<string, object>();
private static string CacheKey;
void IResourceFilter.OnResourceExecuting(ResourceExecutingContext context)
{
CacheKey = context.HttpContext.Request.Path.Value;
//检查缓存中是否存在数据
if (Cache.TryGetValue(CacheKey, out var cacheValue))
{
//如果存在数存在,直接返回
context.Result = new ObjectResult(cacheValue)
{
StatusCode = 200,
};
}
}
void IResourceFilter.OnResourceExecuted(ResourceExecutedContext context)
{
// 如果缓存中不存在数据,将数据添加到缓存中
if (!Cache.ContainsKey(CacheKey))
{
Cache.Add(CacheKey, context.Result);
}
}
}
}
4、异常处理过滤器
异常处理过滤器(Exception Filters)在 ASP.NET Core 中用于捕获控制器动作或整个控制器中抛出的异常。这些过滤器可以用于日志记录、异常转换、返回自定义错误响应等。通过使用异常处理过滤器,开发者可以统一处理错误,而无需在每个控制器或动作方法中重复相同的错误处理逻辑。
使用场景
异常处理过滤器通常用于:
- 错误日志记录:记录错误详细信息,例如堆栈跟踪、请求信息等。
- 统一错误响应格式:确保所有API错误都返回一致的响应格式。
- 异常转换:将特定类型的异常转换为更具体的HTTP状态码或错误消息。
- 异常处理策略:根据不同的异常类型或内容应用不同的处理策略。
using Microsoft.AspNetCore.Mvc.Filters;
namespace AopDemo.Filter
{
public class LoggingActionFilter : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext context)
{
// 在Action方法执行之前执行
//从请求中获取服务的provider
var logger = context.HttpContext.RequestServices.GetService(typeof(ILogger<LoggingActionFilter>)) as ILogger<LoggingActionFilter>;
var path = context.HttpContext.Request.Path;
var controllerName = context.RouteData.Values["controller"];
var actionName = context.RouteData.Values["action"];
var actionArguments = string.Join(",", context.ActionArguments.Select(a => a.Key + ":" + a.Value));
logger.LogInformation($"Action开始执行:{controllerName}.{actionName},参数:{actionArguments}");
// 这里可以写一些逻辑代码
}
public override void OnActionExecuted(ActionExecutedContext context)
{
// 在Action方法执行后执行
// 这里可以写一些逻辑代码
}
}
}
5、操作过滤器
ActionFilter
是一种常见的过滤器,用于拦截和操作控制器的动作方法请求和响应。它是 ASP.NET Core 中过滤器管道的一部分,可以用于跨多个控制器或动作执行逻辑。
日志记录
using Microsoft.AspNetCore.Mvc.Filters;
namespace AopDemo.Filter
{
public class LoggingActionFilter : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext context)
{
// 在Action方法执行之前执行
//从请求中获取服务的provider
var logger = context.HttpContext.RequestServices.GetService(typeof(ILogger<LoggingActionFilter>)) as ILogger<LoggingActionFilter>;
var path = context.HttpContext.Request.Path;
var controllerName = context.RouteData.Values["controller"];
var actionName = context.RouteData.Values["action"];
var actionArguments = string.Join(",", context.ActionArguments.Select(a => a.Key + ":" + a.Value));
logger.LogInformation($"Action开始执行:{controllerName}.{actionName},参数:{actionArguments}");
// 这里可以写一些逻辑代码
}
public override void OnActionExecuted(ActionExecutedContext context)
{
// 在Action方法执行后执行
// 这里可以写一些逻辑代码
}
}
}
验证
在 ActionFilter
中检查模型是否有效,避免在每个动作方法中重复验证逻辑
public class ValidateModelAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext context)
{
if (!context.ModelState.IsValid)
{
context.Result = new BadRequestObjectResult(context.ModelState);
}
}
}