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
相关产品推荐
相关产品推荐

