У меня есть сборка API в .net core 2.1. Чтобы ограничить доступ к различным конечным точкам, я использую IdentityServer4 и атрибут [Authorize]. Тем не менее, моя цель во время разработки состоит в том, чтобы представить документацию API swagger нашим разработчикам, чтобы они могли использовать ее независимо от того, где они работают. Проблема, с которой я сталкиваюсь, заключается в том, как защитить файл swagger index.html, чтобы только они могли видеть детали API.
Я создал собственный файл index.html в папке wwwroot/swagger/ui, и все работает, однако этот файл использует данные из конечной точки /swagger/v1/swagger.json, которая не защищена. Я хотел бы знать, как я могу переопределить возвращаемое значение для этой конкретной конечной точки, чтобы я мог добавить к ней свою собственную аутентификацию?
Обновлено:
В настоящее время я достиг вышеуказанного с помощью следующего промежуточного программного обеспечения:
public class SwaggerInterceptor
{
private readonly RequestDelegate _next;
public SwaggerInterceptor(RequestDelegate next)
{
_next = next;
}
public async Task Invoke(HttpContext context)
{
var uri = context.Request.Path.ToString();
if (uri.StartsWith("/swagger/ui/index.html"))
{
var param = context.Request.QueryString.Value;
if (!param.Equals("?key=123"))
{
context.Response.StatusCode = 404;
context.Response.ContentType = "application/json";
await context.Response.WriteAsync("{\"result:\" \"Not Found\"}", Encoding.UTF8);
return;
}
}
await _next.Invoke(context);
}
}
public class Startup
{
//omitted code
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.UseMiddleware<SwaggerInterceptor>();
//omitted code
}
}
Что мне не нравится в этом подходе, так как он будет проверять каждый запрос. Есть ли лучший способ добиться этого? Вышеприведенное защищает только файл index.html, но я могу настроить его для защиты конечной точки json аналогичным образом.
Также смотрите обсуждение на Как ограничить доступ к папке swagger/*?





Я считаю, что ваш лучший вариант - это то, что вы уже сделали. Создайте собственное промежуточное программное обеспечение, поскольку я не знаю никакого промежуточного программного обеспечения для проверки подлинности статических файлов. Вы можете добавить basePath, чтобы избежать входа в это конкретное промежуточное ПО, когда в этом нет необходимости. Как код ниже
app.Map("/swagger", (appBuilder) =>
{
appBuilder.UseMiddleware<SwaggerInterceptor>();
});
Также эта статья может помочь вам создать более универсальное промежуточное ПО для проверки подлинности статических файлов. https://odetocode.com/blogs/scott/archive/2015/10/06/authorization-policies-and-middleware-in-asp-net-5.aspx
выше ссылка битая
Вы можете выбрать несколько вариантов:
В этом случае вы просто закрываете конечные точки чванства.
// Startup.cs
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
...
services.AddAuthentication()
.AddScheme<BasicAuthenticationOptions, BasicAuthenticationHandler>("Basic", _ => {});
...
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
...
app.UseEndpoints(endpoints =>
{
...
var pipeline = endpoints.CreateApplicationBuilder().Build();
var basicAuthAttr = new AuthorizeAttribute { AuthenticationSchemes = "Basic" };
endpoints
.Map("/swagger/{documentName}/swagger.json", pipeline)
.RequireAuthorization(basicAuthAttr);
endpoints
.Map("/swagger/index.html", pipeline)
.RequireAuthorization(basicAuthAttr);
});
}
}
// BasicAuthenticationHandler.cs
public class BasicAuthenticationHandler : AuthenticationHandler<BasicAuthenticationOptions>
{
...
}
На этот случай я написал статью: https://medium.com/dev-genius/csharp-protecting-swagger-endpoints-82ae5cfc7eb1
Здесь используется OpenIdConnect и Swashbuckle в Asp.Net Core 3.1. Теперь, если я наберу https://myurl.com/swagger, меня перенаправят на мою обычную страницу входа в систему, и после успешного входа я смогу увидеть swagger.
public class Startup
{
//<snip/>
public void Configure(IApplicationBuilder app)
{
//<snip/>
app.UseAuthentication();
app.UseAuthorization();
app.UseSwagger();
app.UseSwaggerUI(c => { c.SwaggerEndpoint("v1/swagger.json", "Some name"); });
app.UseEndpoints(routes =>
{
var pipeline = routes.CreateApplicationBuilder().Build();
routes.Map("/swagger", pipeline).RequireAuthorization(new AuthorizeAttribute {AuthenticationSchemes = OpenIdConnectDefaults.AuthenticationScheme});
routes.Map("/swagger/index.html", pipeline).RequireAuthorization(new AuthorizeAttribute {AuthenticationSchemes = OpenIdConnectDefaults.AuthenticationScheme});
routes.Map("/swagger/v1/swagger.json", pipeline).RequireAuthorization(new AuthorizeAttribute { AuthenticationSchemes = OpenIdConnectDefaults.AuthenticationScheme });
routes.Map("/swagger/{documentName}/swagger.json", pipeline).RequireAuthorization(new AuthorizeAttribute { AuthenticationSchemes = OpenIdConnectDefaults.AuthenticationScheme });
routes.MapDefaultControllerRoute();
});
}
}
Обновлено:
Почему-то я думал, что нижеприведенное работает, но когда я повторно протестировал его позже, оказалось, что на самом деле это выдавало ошибку: запрос достиг конца конвейера без выполнения конечной точки. Итак, я изменился, включив в /swagger фиксированный набор конечных точек, которые, на самом деле, содержат ключевые данные.
route.Map("/swagger/{**any}", конвейер).RequireAuthorization(new AuthorizeAttribute {AuthenticationSchemes = OpenIdConnectDefaults.AuthenticationScheme});
Примечание: эта {**любая} часть шаблона маршрута также защищает все файлы в каталоге /swagger, например, /swagger/index.html, /swagger/v1/swagger.json и т. д. и т. д.
Примечания: Проверка каждого отдельного запроса — очень «дешевая» операция. Кроме того, все, кто хочет иметь дело с Swashbuckle и OpenIdConnect, см. stackoverflow.com/a/65094653/6795110