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

Nswag IOperationProcessor运行时调用配置及权限过滤实现问询

NSwag动态权限过滤接口解决方案

你遇到的问题核心是NSwag默认会预先生成并缓存Swagger文档,导致IOperationProcessor只在文档生成阶段(编译/启动时)执行,无法在每次Swagger页面请求时动态处理权限。下面是适配NSwag的实现方案:

1. 关闭NSwag文档缓存

首先要禁用NSwag的文档缓存,确保每次请求Swagger文档时都重新生成:

services.AddOpenApiDocument(settings =>
{
    // 禁用文档缓存,强制每次请求重新生成
    settings.DocumentProcessorCacheDuration = TimeSpan.Zero;
    // 其他原有配置...
});

2. 自定义动态文档提供者

替换默认的文档生成逻辑,实现IDocumentProvider来在每次请求时解析Cookie令牌并过滤接口:

public class DynamicPermissionDocumentProvider : IDocumentProvider
{
    private readonly OpenApiDocumentGenerator _generator;
    private readonly IHttpContextAccessor _httpContextAccessor;

    public DynamicPermissionDocumentProvider(OpenApiDocumentGenerator generator, IHttpContextAccessor httpContextAccessor)
    {
        _generator = generator;
        _httpContextAccessor = httpContextAccessor;
    }

    public async Task<OpenApiDocument> GetDocumentAsync(string documentName, CancellationToken cancellationToken = default)
    {
        // 生成基础文档
        var document = await _generator.GenerateAsync(documentName, cancellationToken);
        
        // 获取当前请求的HttpContext
        var context = _httpContextAccessor.HttpContext;
        if (context == null)
        {
            // 无上下文时返回空文档
            document.Paths.Clear();
            return document;
        }

        // 从Cookie中获取令牌
        var token = context.Request.Cookies["你的令牌Cookie名称"];
        if (string.IsNullOrEmpty(token))
        {
            // 无令牌时清空所有接口
            document.Paths.Clear();
            return document;
        }

        // 解析令牌,获取用户可访问的控制器/操作声明
        var claimsPrincipal = ParseTokenToClaimsPrincipal(token);
        var allowedOperations = GetAllowedOperationsFromClaims(claimsPrincipal);

        // 过滤文档中的接口
        var pathsToRemove = new List<string>();
        foreach (var path in document.Paths)
        {
            var operationsToRemove = new List<OperationType>();
            foreach (var operation in path.Value.Operations)
            {
                // 从OperationId中解析控制器和Action名称(格式需匹配你的项目配置)
                var operationId = operation.Value.OperationId;
                var parts = operationId.Split('_');
                if (parts.Length != 2 || !allowedOperations.Contains($"{parts[0]}.{parts[1]}"))
                {
                    operationsToRemove.Add(operation.Key);
                }
            }

            foreach (var op in operationsToRemove)
            {
                path.Value.Operations.Remove(op);
            }

            // 路径下无剩余操作则移除整个路径
            if (!path.Value.Operations.Any())
            {
                pathsToRemove.Add(path.Key);
            }
        }

        foreach (var path in pathsToRemove)
        {
            document.Paths.Remove(path);
        }

        return document;
    }

    // 替换为你实际的令牌解析逻辑
    private ClaimsPrincipal ParseTokenToClaimsPrincipal(string token)
    {
        var handler = new JwtSecurityTokenHandler();
        var jwtToken = handler.ReadJwtToken(token);
        return new ClaimsPrincipal(new ClaimsIdentity(jwtToken.Claims, "Bearer"));
    }

    // 从声明中提取用户可访问的控制器.操作列表
    private IEnumerable<string> GetAllowedOperationsFromClaims(ClaimsPrincipal claimsPrincipal)
    {
        var allowedOpsClaim = claimsPrincipal.FindFirst("AllowedOperations")?.Value;
        return allowedOpsClaim?.Split(',') ?? Enumerable.Empty<string>();
    }
}

3. 注册自定义文档提供者

在Startup/Program.cs中注册自定义提供者,替换默认实现:

services.AddHttpContextAccessor(); // 必须注册以获取HttpContext

services.AddOpenApiDocument(settings =>
{
    settings.DocumentProcessorCacheDuration = TimeSpan.Zero;
    // 其他原有配置...
});

// 替换默认的IDocumentProvider
services.AddTransient<IDocumentProvider, DynamicPermissionDocumentProvider>();

4. 配置Swagger UI传递Cookie

确保Swagger UI请求文档时携带Cookie,需开启withCredentials:

services.AddSwaggerUi(settings =>
{
    settings.WithCredentials = true; // 允许请求携带Cookie
    // 其他原有配置...
});

这样配置后,每次刷新Swagger页面时,NSwag都会调用自定义文档提供者的GetDocumentAsync方法,从当前请求的Cookie解析令牌,动态过滤用户无权限访问的接口,实现和Swashbuckle方案一致的动态权限控制效果。

内容的提问来源于stack exchange,提问作者Nando

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 11:42:09