Asp.NET Core 2.2: специфичное для Swagger определение безопасности для конечной точки - PullRequest
1 голос
/ 04 ноября 2019

Я использую Swashbuckle.AspNetCore 5.0.0-rc2 в одном из моих проектов .Net Core 2.2 REST. В рамках моего проекта я обслуживаю два разных API, которые логически связаны друг с другом.

Сегодня мне удалось разделить мою документацию по сваггерам, чтобы иметь по одной конечной точке сваггера на API, содержащей только соответствующие контроллеры API.

Мне удалось сделать это, добавив определенное имя группы в настройки контроллеров api:

[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
[ApiExplorerSettings(GroupName = "contracts")]
public class ContractsController : BaseController

[Authorize(AuthenticationSchemes = "BasicAuthentication")]
[ApiExplorerSettings(GroupName = "clearing")]
public class ClearingController : BaseController

С этими настройками я смог указать разные конечные точки для сваггера в моемStartup.cs

  // Enable documentation middleware
  app.UseSwagger(so =>
  {
    so.RouteTemplate = "api/doc/{documentName}/swagger.json";
  });
  app.UseSwaggerUI(suo =>
  {
    suo.SwaggerEndpoint("/api/doc/contracts/swagger.json", "Contracts API");
    suo.SwaggerEndpoint("/api/doc/clearing/swagger.json", "Clearing API");
    suo.RoutePrefix = "api/doc";
    suo.SupportedSubmitMethods(SubmitMethod.Get, SubmitMethod.Post, SubmitMethod.Patch, SubmitMethod.Delete);
  });

Это сработало, и все было хорошо.

Теперь, как вы, наверное, заметили, я использую разные методы авторизации для контроллеров каждого API. Первый, контрактный API, использует авторизацию токена JWT, а второй, очищающий API, использует базовую авторизацию.

Я думал, что пользователь swagger автоматически использует правильный метод авторизации с помощью атрибута «Authorize», но я ошибся.

Ну, я добавил оба метода авторизации для промежуточного ПО Swagger UI, как это:

  options.AddSecurityDefinition("Bearer", GetSwaggerTokenSecurityScheme());
  options.AddSecurityDefinition("Basic", GetSwaggerBasicSecurityScheme());

  options.AddSecurityRequirement(GetSwaggerJwtSecurityRequirement());
  options.AddSecurityRequirement(GetSwaggerBasicSecurityRequirement());

Вот мой полный код конфигурации Swagger:

/// <summary>
/// Configures the swagger generation
/// </summary>
/// <param name="config">The swagger configuration</param>
/// <param name="options">The swagger gen options instance</param>
public static void ConfigureSwaggerGen(IConfiguration config, SwaggerGenOptions options)
{
  var swaggerConfig = config.Get<SwaggerConfiguration>();
  AddSwaggerDocPerApiType(swaggerConfig, options);

  options.AddSecurityDefinition("Bearer", GetSwaggerTokenSecurityScheme());
  options.AddSecurityDefinition("Basic", GetSwaggerBasicSecurityScheme());

  options.AddSecurityRequirement(GetSwaggerJwtSecurityRequirement());
  options.AddSecurityRequirement(GetSwaggerBasicSecurityRequirement());

  if (!swaggerConfig.SwaggerIncludeXml)
  {
    return;
  }
  var xmlFiles = Directory.GetFiles(AppContext.BaseDirectory, "*.xml");
  xmlFiles.ToList().ForEach(f => options.IncludeXmlComments(f));
  options.DescribeAllEnumsAsStrings();
}

/// <summary>
/// Adds a swagger documentation for each api type
/// </summary>
/// <param name="config">The swagger configuration</param>
/// <param name="options">The swagger gen options instance</param>
private static void AddSwaggerDocPerApiType(SwaggerConfiguration config, SwaggerGenOptions options)
{
  options.SwaggerDoc("contracts", GetSwaggerInformationParams(config, "Contracts"));
  options.SwaggerDoc("clearing", GetSwaggerInformationParams(config, "Clearing"));
}

/// <summary>
/// Generates swagger information params object
/// according to the given configuration
/// </summary>
/// <param name="config">The configuration</param>
/// <param name="apiType">The api type</param>
/// <returns>The swagger information</returns>
private static OpenApiInfo GetSwaggerInformationParams(SwaggerConfiguration config, string apiType = "")
{
  var title = string.IsNullOrEmpty(apiType) ? config.SwaggerTitle : apiType;
  var version = string.IsNullOrEmpty(apiType) ? Assembly.GetExecutingAssembly().GetName().Version.ToString() : apiType;

  var swaggerInfo = new OpenApiInfo()
  {
    Title = title,
    Version = version.ToLower(),
    Description = config.SwaggerDescription,
    Contact = new OpenApiContact()
    {
      Name = config.SwaggerCompany,
      Email = config.SwaggerContactMail,
      Url = new Uri(config.SwaggerContactUrl)
    }
  };
  return swaggerInfo;
}

/// <summary>
/// Generates the swagger jwt security scheme object
/// </summary>
/// <returns>The swagger jwt security scheme</returns>
private static OpenApiSecurityScheme GetSwaggerTokenSecurityScheme()
{
  var scheme = new OpenApiSecurityScheme
  {
    Description = "JWT authorization header using the Bearer scheme. Example: \"Authorization: Bearer {token}\"",
    Name = "JwtAuthorization",
    In = ParameterLocation.Header,
    Type = SecuritySchemeType.ApiKey
  };
  return scheme;
}

/// <summary>
/// Generates the swagger basic security scheme object
/// </summary>
/// <returns>The swagger basic security scheme</returns>
private static OpenApiSecurityScheme GetSwaggerBasicSecurityScheme()
{
  var scheme = new OpenApiSecurityScheme
  {
    Description = "Basic authorization header. Example: \"Authorization: username:password\"",
    Name = "BasicAuthorization",
    In = ParameterLocation.Header,
    Type = SecuritySchemeType.Http,
    Scheme = "basic"
  };
  return scheme;
}

/// <summary>
/// Generates the swagger security scheme object
/// </summary>
/// <returns>The swagger security scheme</returns>
private static OpenApiSecurityRequirement GetSwaggerJwtSecurityRequirement()
{
  var req = new OpenApiSecurityRequirement()
  {
    {
      new OpenApiSecurityScheme()
      {
        Reference = new OpenApiReference() {Type = ReferenceType.SecurityScheme, Id = "Bearer"}
      },
      new[] {"readAccess", "writeAccess"}
    }
  };
  return req;
}

/// <summary>
/// Generates the swagger security scheme object
/// </summary>
/// <returns>The swagger security scheme</returns>
private static OpenApiSecurityRequirement GetSwaggerBasicSecurityRequirement()
{
  var req = new OpenApiSecurityRequirement()
  {
    {
      new OpenApiSecurityScheme()
      {
        Reference = new OpenApiReference() {Type = ReferenceType.SecurityScheme, Id = "Basic"}
      },
      new[] {"readAccess", "writeAccess"}
    }
  };
  return req;
}

Теперь, что я хочуДостигается то, что для контроллеров API контрактов доступна только авторизация токена JWT, а для очищающих контроллеров API доступна только базовая авторизация.

На данный момент у меня всегда есть оба метода авторизации для любого API:

enter image description here

Кто-нибудь знает, как задать защиту только для конкретной конечной точки документации?

С уважением

...