【问题标题】:.NET-5 Hide swagger endpoints to unauthorized users.NET-5 向未经授权的用户隐藏招摇的端点
【发布时间】:2021-04-29 03:26:35
【问题描述】:

我有一个使用 OpenApi 的 .NET 5 API。

是否可以在 swagger 中隐藏所有 API 端点,但登录一个,直到用户获得 JWT 持有者令牌授权?

这是我在 startup.cs 中使用的代码

services.AddSwaggerGen(c =>
        {
            c.SwaggerDoc("v1", new OpenApiInfo { 
                Title = "API", Version = "v1",
                Description = "API (.NET 5.0)",
                Contact = new OpenApiContact()
                {
                    Name = "Contact",
                    Url = null,
                    Email = "email@email.com"
                }
            });
            c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
            {
                Description = @"Autorización JWT utilizando el esquema Bearer en header. <br />
                  Introducir el token JWT generado por AuthApi.",
                Name = "Authorization",
                In = ParameterLocation.Header,
                Type = SecuritySchemeType.Http,
                Scheme = "Bearer"
            });
            c.AddSecurityRequirement(new OpenApiSecurityRequirement()
  {
    {
      new OpenApiSecurityScheme
      {
        Reference = new OpenApiReference
          {
            Type = ReferenceType.SecurityScheme,
            Id = "Bearer"
          },
          Scheme = "oauth2",
          Name = "Bearer",
          In = ParameterLocation.Header,

        },
        new List<string>()
      }
    });
        });

【问题讨论】:

  • 您找到解决方案了吗?我也有同样的问题。
  • @JJJulien 是的,我最终是根据 appsettings.json 参数做的,但我发布了代码。希望对你有帮助

标签: swagger-ui openapi .net-5


【解决方案1】:

您需要实现自己的中间件并检查端点路径。如果它以“/swagger”开头,那么您应该挑战身份验证。

以下代码由其他人 here 编写

using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Builder;
using System;

/// <summary>
/// The extension methods that extends <see cref="IApplicationBuilder" /> for authentication purposes
/// </summary>
public static class ApplicationBuilderExtensions
{
    /// <summary>
    /// Requires authentication for paths that starts with <paramref name="pathPrefix" />
    /// </summary>
    /// <param name="app">The application builder</param>
    /// <param name="pathPrefix">The path prefix</param>
    /// <returns>The application builder</returns>
    public static IApplicationBuilder RequireAuthenticationOn(this IApplicationBuilder app, string pathPrefix)
    {
        return app.Use((context, next) =>
        {
            // First check if the current path is the swagger path
            if (context.Request.Path.HasValue && context.Request.Path.Value.StartsWith(pathPrefix, StringComparison.InvariantCultureIgnoreCase))
            {
                // Secondly check if the current user is authenticated
                if (!context.User.Identity.IsAuthenticated)
                {
                    return context.ChallengeAsync();
                }
            }

            return next();
        });
    }
}

然后在您的 startup.cs 中(以下顺序很重要)

app.RequireAuthenticationOn("/swagger");
app.UseSwagger();
app.UseSwaggerUI();

【讨论】:

    【解决方案2】:

    我最终使用 appsettings.json 参数隐藏了 swagger enpoints,这并不完全符合我的要求,但我会发布解决方案以防它可能有助于过滤登录用户:

    有一些注释块和未使用的代码可能对您有用,就像我在网上找到的示例一样。

    Swagger 忽略过滤器类:

    public class SwaggerIgnoreFilter : IDocumentFilter
    {
        private IServiceProvider _provider;
    
        public SwaggerIgnoreFilter(IServiceProvider provider)
        {
            if (provider == null) throw new ArgumentNullException(nameof(provider));
    
            this._provider = provider;
        }
        public void Apply(OpenApiDocument swaggerDoc, DocumentFilterContext context)
        {
            var allTypes = AppDomain.CurrentDomain.GetAssemblies().SelectMany(i => i.GetTypes()).ToList();
    
            var http = this._provider.GetRequiredService<IHttpContextAccessor>();
            var authorizedIds = new[] { "00000000-1111-2222-1111-000000000000" };   // All the authorized user id's.
                                                                                    // When using this in a real application, you should store these safely using appsettings or some other method.
            var userId = http.HttpContext.User.Claims.Where(x => x.Type == "jti").Select(x => x.Value).FirstOrDefault();
            var show = http.HttpContext.User.Identity.IsAuthenticated && authorizedIds.Contains(userId);
            //var Securitytoken = new JwtSecurityTokenHandler().CreateToken(tokenDescriptor);
            //var tokenstring = new JwtSecurityTokenHandler().WriteToken(Securitytoken);
            //var token = new JwtSecurityTokenHandler().ReadJwtToken(tokenstring);
            //var claim = token.Claims.First(c => c.Type == "email").Value;
            Parametros parametros = new Parametros();
            if (!show)
            {
                var descriptions = context.ApiDescriptions.ToList();
    
                foreach (var description in descriptions)
                {
                    // Expose login so users can login through Swagger. 
                    if (description.HttpMethod == "POST" && description.RelativePath == "denarioapi/v1/auth/login")
                        continue;
    
                    var route = "/" + description.RelativePath.TrimEnd('/');
                    OpenApiPathItem path;
                    swaggerDoc.Paths.TryGetValue(route, out path);
    
                    switch(route)
                    {
                        case string s when s.Contains("/Contabilidad"):
                            if (parametros.contabilidadApi != "1")
                            {
                                swaggerDoc.Paths.Remove(route);
                            }
                            break;
                        case string s when s.Contains("/Identificativos"):
                            if (parametros.identificativosApi != "1")
                            {
                                swaggerDoc.Paths.Remove(route);
                            }
                            break;
                        case string s when s.Contains("/Centros"):
                            if (parametros.centrosApi != "1")
                            {
                                swaggerDoc.Paths.Remove(route);
                            }
                            break;
                        case string s when s.Contains("/Contratos"):
                            if (parametros.contratosApi != "1")
                            {
                                swaggerDoc.Paths.Remove(route);
                            }
                            break;
                        
                        case string s when s.Contains("/Planificacion"):
                            if (parametros.planificacionApi != "1")
                            {
                                swaggerDoc.Paths.Remove(route);
                            }
                            break;
                        case string s when s.Contains("/Puestotrabajo"):
                            if (parametros.puestotrabajoApi != "1")
                            {
                                swaggerDoc.Paths.Remove(route);
                            }
                            break;
                        
                        case string s when s.Contains("/Usuarios"):
                            if (parametros.usuariosApi != "1")
                            {
                                swaggerDoc.Paths.Remove(route);
                            }
                            break;
                        
                        default:
                            break;
                    }
    
                    // remove method or entire path (if there are no more methods in this path)
                    //switch (description.HttpMethod)
                    //{
                        //case "DELETE": path. = null; break;
                        //case "GET": path.Get = null; break;
                        //case "HEAD": path.Head = null; break;
                        //case "OPTIONS": path.Options = null; break;
                        //case "PATCH": path.Patch = null; break;
                        //case "POST": path.Post = null; break;
                        //case "PUT": path.Put = null; break;
                        //default: throw new ArgumentOutOfRangeException("Method name not mapped to operation");
                    //}
    
                    //if (path.Delete == null && path.Get == null &&
                    //    path.Head == null && path.Options == null &&
                    //    path.Patch == null && path.Post == null && path.Put == null)
                    //swaggerDoc.Paths.Remove(route);
                }
    
            }
    
    
    
    
            foreach (var definition in swaggerDoc.Components.Schemas)
            {
                var type = allTypes.FirstOrDefault(x => x.Name == definition.Key);
                if (type != null)
                {
                    var properties = type.GetProperties();
                    foreach (var prop in properties.ToList())
                    {
                        var ignoreAttribute = prop.GetCustomAttribute(typeof(OpenApiIgnoreAttribute), false);
    
                        if (ignoreAttribute != null)
                        {
                            definition.Value.Properties.Remove(prop.Name);
                        }
                    }
                }
            }
        }
    }
    

    Startup.cs 配置服务:

    services.AddSwaggerGen(c =>
            {
                c.SwaggerDoc("v1", new OpenApiInfo
                {
                    Title = "API",
                    Version = "v1",
                    Description = "API (.NET 5.0)",
                    Contact = new OpenApiContact()
                    {
                        Name = "Contact name",
                        Url = null,
                        Email = "email@email.com"
                    }
                });
                c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
                {
                    Description = @"Description",
                    Name = "Authorization",
                    In = ParameterLocation.Header,
                    Type = SecuritySchemeType.Http,
                    Scheme = "Bearer"
                });
                c.DocumentFilter<SwaggerIgnoreFilter>();
                c.AddSecurityRequirement(new OpenApiSecurityRequirement()
      {
            {
              new OpenApiSecurityScheme
              {
                Reference = new OpenApiReference
                  {
                    Type = ReferenceType.SecurityScheme,
                    Id = "Bearer"
                  },
                  Scheme = "oauth2",
                  Name = "Bearer",
                  In = ParameterLocation.Header,
    
                },
                new List<string>()
              }
        });
            });
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-09-10
      • 1970-01-01
      • 2021-09-23
      • 2015-10-29
      • 1970-01-01
      • 1970-01-01
      • 2019-10-12
      相关资源
      最近更新 更多