如何有选择地将OperationFilter添加到Swagger中的API端点?

Jet*_*Cao 8 c# http-headers swagger asp.net-core

我有以下IOperationFilter类,它实现了 API 应用程序中某些端点所需的身份验证标头:

public class AuthenticationHeadersFilter : IOperationFilter
{
    public void Apply(OpenApiOperation operation, OperationFilterContext context)
    {
        if (operation.Parameters == null)
            operation.Parameters = new List<OpenApiParameter>();

        operation.Parameters.Add(new OpenApiParameter
            {
                Name = "AccountName",
                In = ParameterLocation.Header,
                Required = true
            });

        operation.Parameters.Add(new OpenApiParameter
            {
                Name = "ApiKey",
                In = ParameterLocation.Header,
                Required = true
            });
    }
}
Run Code Online (Sandbox Code Playgroud)

ConfigureServices上面的内容通过以下方法添加到我的应用程序的 Swagger UI 中Startup.cs

public class AuthenticationHeadersFilter : IOperationFilter
{
    public void Apply(OpenApiOperation operation, OperationFilterContext context)
    {
        if (operation.Parameters == null)
            operation.Parameters = new List<OpenApiParameter>();

        operation.Parameters.Add(new OpenApiParameter
            {
                Name = "AccountName",
                In = ParameterLocation.Header,
                Required = true
            });

        operation.Parameters.Add(new OpenApiParameter
            {
                Name = "ApiKey",
                In = ParameterLocation.Header,
                Required = true
            });
    }
}
Run Code Online (Sandbox Code Playgroud)

这很好用,但是我现在也有一些端点,我希望通过 Swagger 记录/显示这些端点,但应该完全可以公开访问,而不需要用户在其 API 请求中提供 和 作为AccountNameApiKey头。我怎样才能做到这一点?

我找到了这个 Stack Overflow 答案,但不确定它是否可以适应我的目的。我找不到有关该OperationFilterContext课程的任何有用的文档。

任何帮助是极大的赞赏。

Iva*_*kov 11

There is SwaggerOperationFilter attribute specifically for this case.

You need to install package Swashbuckle.AspNetCore.Annotations and enable it:

// Startup.cs
services.AddSwaggerGen(c =>
{
    ...
    c.EnableAnnotations();
};
Run Code Online (Sandbox Code Playgroud)

Then you can use it like [SwaggerOperationFilter(typeof(YourFilterClass))] instead of c.OperationFilter<YourFilterClass>();


小智 8

可能的解决方案可能是拥有这样的属性

using System;

namespace some.namespace
{
    [AttributeUsage(AttributeTargets.Method | AttributeTargets.Class)]
    public class SkipAuthenticationHeadersAttribute : Attribute
    {
    }
}
Run Code Online (Sandbox Code Playgroud)

并在 swagger AuthenticationHeadersFilter 中使用它,如下所示:

using System.Linq;
using Microsoft.OpenApi.Any;
using Microsoft.OpenApi.Models;
using Swashbuckle.AspNetCore.SwaggerGen;

namespace some.namespace
{
    /// <summary>
    /// https://alexdunn.org/2018/06/29/adding-a-required-http-header-to-your-swagger-ui-with-swashbuckle/.
    /// </summary>
    public class AuthenticationHeadersFilter : IOperationFilter
    {
        /// <summary>
        /// Swagger: Creates new required http header.
        /// </summary>
        /// <param name="operation"> Open Api Operation.</param>
        /// <param name="context">Operation Filter Context.</param>
        public void Apply(OpenApiOperation operation, OperationFilterContext context)
        {
            var globalAttributes = context.ApiDescription.ActionDescriptor.FilterDescriptors.Select(p => p.Filter);
            var controllerAttributes = context.MethodInfo?.DeclaringType?.GetCustomAttributes(true);
            var methodAttributes = context.MethodInfo?.GetCustomAttributes(true);
            var produceAttributes = globalAttributes
                .Union(controllerAttributes ?? throw new InvalidOperationException())
                .Union(methodAttributes)
                .OfType<SkipAuthenticationHeadersAttribute>()
                .ToList();

            if (produceAttributes.Count != 0)
            {
                return;
            }

            if (operation.Parameters == null)
            {
                operation.Parameters = new List<OpenApiParameter>();
            }

            operation.Parameters.Add(new OpenApiParameter
            {
               Name = "AccountName",
               In = ParameterLocation.Header,
               Required = true
            });

            operation.Parameters.Add(new OpenApiParameter
            {
               Name = "ApiKey",
               In = ParameterLocation.Header,
               Required = true
            });
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

因此,当您将属性添加到控制器操作时,该操作将被过滤掉。