我在.net core 2.1中有一个api构建。为了限制对各种端点的访问,我使用IdentityServer4和[Authorize]属性。但是,我在开发过程中的目标是向我们的开发人员公开api swagger文档,以便他们无论在哪里工作都可以使用它。我面临的挑战是如何保护swagger index.html文件,以便只有他们才能看到api的详细信息。
我已经在wwwroot / swagger / ui文件夹中创建了一个自定义index.html文件,并且一切正常,但是,该文件使用来自/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端点。
答案 0 :(得分:2)
您可以选择一些选项:
在这种情况下,您只需要关闭摇摇欲坠的端点即可。
// 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
答案 1 :(得分:1)
我相信您最好的选择就是您已经做过的事情。构建您自己的中间件,因为我不知道任何用于验证静态文件的中间件。您可以添加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
答案 2 :(得分:0)
此处使用的是Asp.Net Core 3.1中的OpenIdConnect和Swashbuckle。现在,如果我输入https://myurl.com/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下包含一组固定的端点,这些端点包含afaik关键数据。
routes.Map(“ / swagger / {** any}”,管道).RequireAuthorization(新的AuthorizeAttribute {AuthenticationSchemes = OpenIdConnectDefaults.AuthenticationScheme});
注意:路由模板的{** any}部分也保护了/ swagger下的所有文件,因此,例如/swagger/index.html、/swagger/v1/swagger.json等等。