You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.NET 6中如何统一添加权限策略对应的日志范围以避免重复编码?

解决方案

针对你的需求,有两种简洁的统一实现方式,无需在每个端点重复编写日志逻辑:

方案一:自定义授权过滤器(IAsyncAuthorizationFilter)

授权过滤器属于MVC管道层级,能精准捕获带有指定策略的请求,且可通过包裹后续流程创建日志范围。

实现步骤:

  1. 创建自定义过滤器类:
public class ResourceAccessLoggingFilter : IAsyncAuthorizationFilter
{
    private readonly ILogger<ResourceAccessLoggingFilter> _logger;

    public ResourceAccessLoggingFilter(ILogger<ResourceAccessLoggingFilter> logger)
    {
        _logger = logger;
    }

    public async Task OnAuthorizationAsync(AuthorizationFilterContext context)
    {
        // 检查当前端点是否应用了目标授权策略
        var authorizeAttr = context.ActionDescriptor.EndpointMetadata
            .OfType<AuthorizeAttribute>()
            .FirstOrDefault(a => a.Policy == "MyResourcePolicyName");

        if (authorizeAttr == null)
            return;

        // 从Claims获取用户ID(根据你的认证方式调整)
        var userId = context.HttpContext.User.FindFirstValue(ClaimTypes.NameIdentifier);
        // 从路由参数获取资源集ID(根据实际路由规则调整)
        var resourceSetId = context.RouteData.Values["resourceSetId"]?.ToString();

        // 启动日志范围,包裹后续所有请求处理逻辑
        using (_logger.BeginScope(new Dictionary<string, object>
        {
            ["UserId"] = userId,
            ["ResourceSetId"] = resourceSetId
        }))
        {
            await Task.CompletedTask;
        }
    }
}
  1. 在Program.cs中注册全局过滤器:
builder.Services.AddControllers(options =>
{
    options.Filters.Add<ResourceAccessLoggingFilter>();
});

方案二:自定义中间件检查端点元数据

中间件可在请求流程中提前介入,通过端点元数据判断是否需要添加日志范围,适合覆盖全请求生命周期的记录需求。

实现步骤:

  1. 创建自定义中间件:
public class ResourceAccessLoggingMiddleware
{
    private readonly RequestDelegate _next;
    private readonly ILogger<ResourceAccessLoggingMiddleware> _logger;

    public ResourceAccessLoggingMiddleware(RequestDelegate next, ILogger<ResourceAccessLoggingMiddleware> logger)
    {
        _next = next;
        _logger = logger;
    }

    public async Task InvokeAsync(HttpContext context)
    {
        var endpoint = context.GetEndpoint();
        // 校验端点是否带有目标授权策略
        if (endpoint?.Metadata.GetMetadata<AuthorizeAttribute>() is AuthorizeAttribute authorizeAttr 
            && authorizeAttr.Policy == "MyResourcePolicyName")
        {
            var userId = context.User.FindFirstValue(ClaimTypes.NameIdentifier);
            var resourceSetId = context.Request.RouteValues["resourceSetId"]?.ToString();

            using (_logger.BeginScope(new Dictionary<string, object>
            {
                ["UserId"] = userId,
                ["ResourceSetId"] = resourceSetId
            }))
            {
                await _next(context);
            }
        }
        else
        {
            await _next(context);
        }
    }
}
  1. 在Program.cs中注册中间件(需放在路由中间件之后):
app.UseRouting();

// 注册自定义日志中间件
app.UseMiddleware<ResourceAccessLoggingMiddleware>();

app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
    endpoints.MapControllers();
});

关键注意事项

  • 资源集ID获取:示例从路由参数提取,可根据实际场景调整为从请求体、查询参数等位置获取。
  • 用户ID获取:示例使用ClaimTypes.NameIdentifier,请根据你的认证方案(JWT、Cookie等)替换为对应Claim类型。
  • 日志范围作用:BeginScope会将指定键值对附加到该请求后续的所有日志条目,无需在端点单独重复记录用户和资源信息。

内容的提问来源于stack exchange,提问作者Ben Zuill-Smith

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 18:33:13