如何在 Swagger UI 中发送带有请求的自定义 headers?

How to send custom headers with requests in Swagger UI?

我在 API 中有一些端点 - /user/login/products

在 Swagger UI 我 post emailpassword/user/login 作为响应我收到一个 token 字符串。

然后,我可以从响应中复制令牌,并希望将其用作所有 url 请求中的 Authorization header 值(如果它存在),并将 /products 作为例如。

我应该在 Swagger UI 页面的某处手动创建文本输入,然后将令牌放在那里并以某种方式注入请求,还是有工具可以更好地管理它?

您可以在您的请求中添加一个header参数,Swagger-UI会将其显示为一个可编辑的文本框:

swagger: "2.0"
info:
  version: 1.0.0
  title: TaxBlaster
host: taxblaster.com
basePath: /api
schemes:
- http

paths:

  /taxFilings/{id}:

    get:
      parameters:
      - name: id
        in: path
        description: ID of the requested TaxFiling
        required: true
        type: string
      - name: auth
        in: header
        description: an authorization header
        required: true
        type: string
      responses:
        200:
          description: Successful response, with a representation of the Tax Filing.
          schema:
            $ref: "#/definitions/TaxFilingObject"
        404:
          description: The requested tax filing was not found.

definitions:
  TaxFilingObject:
    type: object
    description: An individual Tax Filing record.
    properties:
      filingID:
        type: string
      year:
        type: string
      period:
        type: integer
      currency:
        type: string
      taxpayer:
        type: object

您还可以添加类型为 apiKey:

的安全定义
swagger: "2.0"
info:
  version: 1.0.0
  title: TaxBlaster
host: taxblaster.com
basePath: /api
schemes:
- http

securityDefinitions:
  api_key:
    type: apiKey
    name: api_key
    in: header
    description: Requests should pass an api_key header.

security: 
 - api_key: []

paths:

  /taxFilings/{id}:

    get:
      parameters:
      - name: id
        in: path
        description: ID of the requested TaxFiling
        required: true
        type: string

      responses:
        200:
          description: Successful response, with a representation of the Tax Filing.
          schema:
            $ref: "#/definitions/TaxFilingObject"
        404:
          description: The requested tax filing was not found.

definitions:
  TaxFilingObject:
    type: object
    description: An individual Tax Filing record.
    properties:
      filingID:
        type: string
      year:
        type: string
      period:
        type: integer
      currency:
        type: string
      taxpayer:
        type: object

securityDefinitions object 定义了安全方案。

security object(在 Swagger–OpenAPI 中称为 "security requirements"),将安全方案应用于给定的上下文。在我们的例子中,我们通过将安全要求声明为顶级来将其应用于整个 API。我们可以选择在单个路径项 and/or 方法中覆盖它。

这是指定安全方案的首选方式;它替换了第一个示例中的 header 参数。不幸的是,Swagger-UI 没有提供文本框来控制这个参数,至少在我目前的测试中是这样。

在 ASP.NET Web API 中,在 Swagger UI 上 pass-in 一个 header 的最简单方法是实现 Apply(...) 方法在 IOperationFilter 接口上。

将此添加到您的项目中:

public class AddRequiredHeaderParameter : IOperationFilter
{
    public void Apply(Operation operation, SchemaRegistry schemaRegistry, ApiDescription apiDescription)
    {
        if (operation.parameters == null)
            operation.parameters = new List<Parameter>();

        operation.parameters.Add(new Parameter
        {
            name = "MyHeaderField",
            @in = "header",
            type = "string",
            description = "My header field",
            required = true
        });
    }
}

SwaggerConfig.cs 中,使用 c.OperationFilter<T>():

从上面注册过滤器
public static void Register()
{
    var thisAssembly = typeof(SwaggerConfig).Assembly;

    GlobalConfiguration.Configuration 
        .EnableSwagger(c =>
        {
            c.SingleApiVersion("v1", "YourProjectName");
            c.IgnoreObsoleteActions();
            c.UseFullTypeNameInSchemaIds();
            c.DescribeAllEnumsAsStrings();
            c.IncludeXmlComments(GetXmlCommentsPath());
            c.ResolveConflictingActions(apiDescriptions => apiDescriptions.First());


            c.OperationFilter<AddRequiredHeaderParameter>(); // Add this here
        })
        .EnableSwaggerUi(c =>
        {
            c.DocExpansion(DocExpansion.List);
        });
}

我最终来到这里是因为我试图根据我自己添加到 API 方法的 [Authentication] 属性,在 Swagger UI 中有条件地添加 header 参数.按照@Corcus 在评论中列出的提示,我能够得出我的解决方案,希望它能帮助其他人。

使用反射检查 apiDescription 中嵌套的方法是否具有所需的属性(在我的例子中为 MyApiKeyAuthenticationAttribute)。如果是这样,我可以附加我想要的 header 参数。

public void Apply(Operation operation, SchemaRegistry schemaRegistry, ApiDescription apiDescription) {
    if (operation.parameters == null)
        operation.parameters = new List<Parameter>();


    var attributes = ((System.Web.Http.Controllers.ReflectedHttpActionDescriptor)
        ((apiDescription.ActionDescriptor).ActionBinding.ActionDescriptor)).MethodInfo
        .GetCustomAttributes(false);
    if(attributes != null && attributes.Any()) {
        if(attributes.Where(x => x.GetType() 
            == typeof(MyApiKeyAuthenticationAttribute)).Any()) {

            operation.parameters.Add(new Parameter {
                name = "MyApiKey",
                @in = "header",
                type = "string",
                description = "My API Key",
                required = true
            });
            operation.parameters.Add(new Parameter {
                name = "EID",
                @in = "header",
                type = "string",
                description = "Employee ID",
                required = true
            });
        }
    }


}

ASP.NET Core 2 Web API中,使用Swashbuckle.AspNetCore包2.1.0,实现一个IDocumentFilter:

SwaggerSecurityRequirementsDocumentFilter.cs

using System.Collections.Generic;
using Swashbuckle.AspNetCore.Swagger;
using Swashbuckle.AspNetCore.SwaggerGen;

namespace api.infrastructure.filters
{
    public class SwaggerSecurityRequirementsDocumentFilter : IDocumentFilter
    {
        public void Apply(SwaggerDocument document, DocumentFilterContext context)
        {
            document.Security = new List<IDictionary<string, IEnumerable<string>>>()
            {
                new Dictionary<string, IEnumerable<string>>()
                {
                    { "Bearer", new string[]{ } },
                    { "Basic", new string[]{ } },
                }
            };
        }
    }
}

在 Startup.cs 中,配置安全定义并注册自定义过滤器:

public void ConfigureServices(IServiceCollection services)
{
    services.AddSwaggerGen(c =>
    {
        // c.SwaggerDoc(.....

        c.AddSecurityDefinition("Bearer", new ApiKeyScheme()
        {
            Description = "Authorization header using the Bearer scheme",
            Name = "Authorization",
            In = "header"
        });

        c.DocumentFilter<SwaggerSecurityRequirementsDocumentFilter>();
    });
}

在 Swagger UI 中,单击“授权”按钮并设置令牌值。

结果:

curl -X GET "http://localhost:5000/api/tenants" -H "accept: text/plain" -H "Authorization: Bearer ABCD123456"

对于那些使用 NSwag 并且需要自定义 header 的人:

app.UseSwaggerUi3(typeof(Startup).GetTypeInfo().Assembly, settings =>
      {
          settings.GeneratorSettings.IsAspNetCore = true;
          settings.GeneratorSettings.OperationProcessors.Add(new OperationSecurityScopeProcessor("custom-auth"));

          settings.GeneratorSettings.DocumentProcessors.Add(
              new SecurityDefinitionAppender("custom-auth", new SwaggerSecurityScheme
                {
                    Type = SwaggerSecuritySchemeType.ApiKey,
                    Name = "header-name",
                    Description = "header description",
                    In = SwaggerSecurityApiKeyLocation.Header
                }));
        });            
    }

Swagger UI 将包含一个 A​​uthorize 按钮。

免责声明:此解决方案不是使用Header。

如果有人正在寻找 lazy-lazy 方式(也在 WebApi 中),我建议:

public YourResult Authorize([FromBody]BasicAuthCredentials credentials)

你不是从 header 那里得到的,但至少你有一个简单的选择。 您始终可以检查 object 是否为 null 并回退到 header 机制。

也可以将属性 [FromHeader] 用于 Web 方法参数(或模型 class 中的属性),这些参数应在自定义 headers 中发送。像这样:

[HttpGet]
public ActionResult Products([FromHeader(Name = "User-Identity")] string userIdentity)

至少它在 ASP.NET Core 2.1 和 Swashbuckle.AspNetCore 2.5.0 上工作正常。

这是 ASP.NET Core Web Api/Swashbuckle 组合的更简单答案,不需要您注册任何自定义过滤器。第三次是你知道的魅力:)。

将下面的代码添加到您的 Swagger 配置中将导致授权按钮出现,允许您输入要为所有请求发送的不记名令牌。不要忘记在询问时将此标记输入为 Bearer <your token here>

请注意,下面的代码将为所有请求和操作发送令牌,这可能是您想要的,也可能不是您想要的。


    services.AddSwaggerGen(c =>
    {
        //...

        c.AddSecurityDefinition("Bearer", new ApiKeyScheme()
        {
            Description = "JWT Authorization header using the Bearer scheme. Example: \"Authorization: Bearer {token}\"",
            Name = "Authorization",
            In = "header",
            Type = "apiKey"
        });

        c.AddSecurityRequirement(new Dictionary<string, IEnumerable<string>>
        {
            { "Bearer", new string[] { } }
        });

        //...
    }

通过this thread.

Golang/go-swagger 示例:https://github.com/go-swagger/go-swagger/issues/1416

// swagger:parameters opid
type XRequestIdHeader struct {
    // in: header
    // required: true
    XRequestId string `json:"X-Request-Id"`
}

...
    // swagger:operation POST /endpoint/ opid
    // Parameters:
    // - $ref: #/parameters/XRequestIDHeader

OpenAPI 3 更新,库 Swashbuckle.AspNetCore。此来源提供了正确的代码示例:https://codeburst.io/api-security-in-swagger-f2afff82fb8e

用于 JWT Bearer 的正确代码是:

services.AddSwaggerGen(c =>
{
    // configure SwaggerDoc and others

    // add JWT Authentication
    var securityScheme = new OpenApiSecurityScheme
    {
        Name = "JWT Authentication",
        Description = "Enter JWT Bearer token **_only_**",
        In = ParameterLocation.Header,
        Type = SecuritySchemeType.Http,
        Scheme = "bearer", // must be lower case
        BearerFormat = "JWT",
        Reference = new OpenApiReference
        {
            Id = JwtBearerDefaults.AuthenticationScheme,
            Type = ReferenceType.SecurityScheme
        }
    };
    c.AddSecurityDefinition(securityScheme.Reference.Id, securityScheme);
    c.AddSecurityRequirement(new OpenApiSecurityRequirement
    {
        {securityScheme, new string[] { }}
    });
}

我看过一篇文章,其中包含类似 OpenAPI 2 的代码,但由于该示例错过了参考定义而浪费了很多时间。这导致 Swashbuckle 生成了不正确的定义并且没有包含授权 header。因此请仔细检查您使用的 OpenAPI 版本。

这就是我在 .NET 6 中的实现方式

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

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

最后

services.AddSwaggerGen(c =>
        {
            c.OperationFilter<AddCustomHeaderParameter>();
        });

如果您正在使用 Nest.js,可以通过在设置 swagger 时添加 addBearerAuth() 来实现(可能在 main.ts 中)。

...........

  const config = new DocumentBuilder()
    .setTitle('Your title')
    .setDescription('Your description')
    .setVersion('1.0')
    .addBearerAuth()   // Add here
    .build();

  const document = SwaggerModule.createDocument(app, config);
  SwaggerModule.setup('api', app, document);

...........

加上这个,我们可以从 Swagger UI 传入 Bearer 令牌,如下所示:

PS: 你必须在各自的控制器中使用 Authguard 来保护你的路由。