【问题标题】:How to protect swagger endpoint in .NET Core API?如何保护 .NET Core API 中的 swagger 端点?
【发布时间】:2019-03-16 17:09:52
【问题描述】:

我在 .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 端点。

【问题讨论】:

标签: c# api swagger asp.net-core-2.0 swagger-ui


【解决方案1】:

您可以选择一些选项:

  • 基本授权
  • 使用身份服务器的 OpenId Connect 授权

基本授权

在这种情况下,您只需关闭 swagger 端点。

// 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>
{
    ...
}

使用 IdentityServer4 进行 OIDC 授权

我为这个案例写过文章:https://medium.com/dev-genius/csharp-protecting-swagger-endpoints-82ae5cfc7eb1

【讨论】:

    【解决方案2】:

    这里是在 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 下包含一组固定的端点,其中包含关键数据。

    routes.Map("/swagger/{**any}", pipeline).RequireAuthorization(new AuthorizeAttribute {AuthenticationSchemes = OpenIdConnectDefaults.AuthenticationScheme});

    注意:路由模板的 {**any} 部分也保护 /swagger 下的所有文件,例如 /swagger/index.html、/swagger/v1/swagger.json 等。

    【讨论】:

      【解决方案3】:

      我相信你最好的选择是你已经做过的。构建您自己的中间件,因为我不知道任何用于验证静态文件身份验证的中间件。您可以添加 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

      【讨论】:

      • 以上链接损坏
      猜你喜欢
      • 2020-12-29
      • 2017-12-04
      • 2020-11-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-11-28
      • 1970-01-01
      • 2017-11-10
      相关资源
      最近更新 更多