You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.NET Core项目中如何隔离内外API的Swagger文档并做权限控制

解决方案:保护Umbraco项目中Swagger内部API文档的访问权限

针对你的Umbraco + .NET Core项目场景,以下是几种可行的实现方案,适配你提到的不同需求:

方案一:独立配置公共/内部Swagger UI + 端点授权

这种方案将公共和内部Swagger文档完全分离,通过中间件严格控制内部文档的访问权限,适合需要强隔离的场景。

步骤1:配置授权策略

在服务注册阶段(Program.cs或Startup.cs)添加授权规则,根据你的认证方式定义内部用户的访问权限:

services.AddAuthorization(options =>
{
    options.AddPolicy("InternalApiAccess", policy =>
    {
        // 示例:要求用户拥有InternalUser角色
        policy.RequireRole("InternalUser");
        // 若使用Umbraco后台身份,可替换为Umbraco内置角色
        // policy.RequireClaim(ClaimTypes.Role, Umbraco.Cms.Core.Security.Constants.Security.AdminRole);
    });
});

步骤2:配置双Swagger UI端点

在管道配置阶段,分别为公共和内部文档设置独立的UI路径,并为内部路径添加授权校验:

// 公共Swagger UI:无需授权,直接访问
app.UseSwaggerUI(c =>
{
    c.RoutePrefix = "swagger/public";
    c.SwaggerEndpoint("/swagger/public/swagger.json", "Public Facing API v1");
    c.SupportedSubmitMethods(new SubmitMethod[] { SubmitMethod.Get, SubmitMethod.Head });
});

// 内部Swagger UI:仅授权用户可访问
app.MapWhen(context => context.Request.Path.StartsWithSegments("/swagger/internal"), internalApp =>
{
    internalApp.UseAuthorization();
    internalApp.UseSwaggerUI(c =>
    {
        c.RoutePrefix = "swagger/internal";
        c.SwaggerEndpoint("/swagger/internal/swagger.json", "Internal API v1");
        c.SupportedSubmitMethods(new SubmitMethod[] { SubmitMethod.Get, SubmitMethod.Head });
    });
});

步骤3:保护内部Swagger JSON端点

直接访问/swagger/internal/swagger.json也能获取内部API信息,需单独对该路径添加授权:

app.MapGet("/swagger/internal/swagger.json", async context =>
{
    // 验证用户权限
    if (!await context.AuthorizeAsync("InternalApiAccess"))
    {
        context.Response.StatusCode = StatusCodes.Status401Unauthorized;
        return;
    }
    // 转发请求到Swagger中间件生成JSON
    await app.ApplicationServices.GetRequiredService<SwaggerMiddleware>().Invoke(context);
}).RequireAuthorization("InternalApiAccess");

方案二:单文档动态过滤API内容

如果希望统一Swagger入口,根据用户身份动态显示公共/内部API,可使用Swashbuckle的DocumentFilter实现。

步骤1:创建文档过滤逻辑

实现IDocumentFilter接口,根据当前用户权限移除未授权的API操作:

public class InternalApiFilter : IDocumentFilter
{
    private readonly IHttpContextAccessor _httpContextAccessor;

    public InternalApiFilter(IHttpContextAccessor httpContextAccessor)
    {
        _httpContextAccessor = httpContextAccessor;
    }

    public void Apply(OpenApiDocument swaggerDoc, DocumentFilterContext context)
    {
        var httpContext = _httpContextAccessor.HttpContext;
        if (httpContext == null) return;

        // 判断用户是否有权限查看内部API
        var canViewInternal = httpContext.User.Identity.IsAuthenticated && 
                              httpContext.User.IsInRole("InternalUser");

        if (!canViewInternal)
        {
            // 移除所有标记为「Internal」的API路径
            var internalPaths = swaggerDoc.Paths
                .Where(p => p.Value.Operations.Any(o => 
                    o.Value.Tags.Any(t => t.Name == "Internal")))
                .ToList();

            foreach (var path in internalPaths)
            {
                swaggerDoc.Paths.Remove(path.Key);
            }
        }
    }
}

步骤2:注册过滤器并标记内部API

在AddSwaggerGen中注册过滤器,同时在内部API控制器/方法上添加[Tags("Internal")]标记:

services.AddSwaggerGen(options =>
{
    options.SwaggerDoc("v1", new OpenApiInfo
    {
        Title = "Combined API",
        Version = "v1",
    });
    // 注册文档过滤器
    options.DocumentFilter<InternalApiFilter>();
});

// 内部API控制器示例
[ApiController]
[Route("api/internal")]
[Tags("Internal")]
public class InternalController : ControllerBase
{
    // 内部API方法...
}

步骤3:配置统一Swagger UI

无需拆分UI,直接配置单入口即可,未授权用户访问时只会看到公共API:

app.UseSwaggerUI(c =>
{
    c.RoutePrefix = "swagger";
    c.SwaggerEndpoint("/swagger/v1/swagger.json", "Combined API v1");
    c.SupportedSubmitMethods(new SubmitMethod[] { SubmitMethod.Get, SubmitMethod.Head });
});

方案三:嵌入Swagger到Umbraco后台(复用Umbraco权限)

如果内部用户已使用Umbraco后台,可将内部Swagger文档嵌入Umbraco后台视图,直接复用Umbraco的权限体系。

步骤1:创建Umbraco后台分部视图

在Views/Partials目录下创建InternalSwagger.cshtml,嵌入Swagger UI资源:

<div id="swagger-ui-container"></div>

<script src="https://cdn.jsdelivr.net/npm/swagger-ui-dist@5/swagger-ui-bundle.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/swagger-ui-dist@5/swagger-ui.css" />

<script>
    window.onload = () => {
        SwaggerUIBundle({
            url: '/swagger/internal/swagger.json',
            dom_id: '#swagger-ui-container',
            presets: [SwaggerUIBundle.presets.apis],
            supportedSubmitMethods: ['get', 'head']
        });
    };
</script>

步骤2:创建授权的Surface控制器

创建控制器返回该视图,并添加Umbraco权限校验:

[Authorize(Policy = Umbraco.Cms.Core.Security.Constants.Security.AdminRole)]
public class InternalSwaggerController : SurfaceController
{
    public IActionResult Index() => PartialView("~/Views/Partials/InternalSwagger.cshtml");
}

步骤3:配置Umbraco后台菜单项

通过Composer添加后台菜单项,仅授权用户可见:

public class SwaggerDashboardComposer : IComposer
{
    public void Compose(IUmbracoBuilder builder)
    {
        builder.Dashboards().AddDashboard<InternalSwaggerDashboard>();
    }
}

[Dashboard(
    Alias = "internalApiDocs",
    Name = "内部API文档",
    Sections = new[] { Umbraco.Cms.Core.Security.Constants.Sections.Settings },
    AccessRules = new[] {
        new AccessRule { Type = AccessRuleType.Role, Value = Umbraco.Cms.Core.Security.Constants.Security.AdminRole }
    })]
public class InternalSwaggerDashboard : IDashboard
{
    public IEnumerable<IComposedDashboard> GetDashboards()
    {
        return new List<IComposedDashboard>
        {
            new ComposedDashboard { ViewPath = "/Views/Partials/InternalSwagger.cshtml" }
        };
    }
}

步骤4:保护内部Swagger JSON端点

确保只有Umbraco授权用户能访问内部API的JSON文档:

app.MapGet("/swagger/internal/swagger.json", async context =>
{
    var umbracoContext = context.RequestServices.GetRequiredService<IUmbracoContextAccessor>().GetRequiredUmbracoContext();
    var currentUser = umbracoContext.Security.CurrentUser;
    
    if (currentUser == null || !currentUser.IsInRole(Umbraco.Cms.Core.Security.Constants.Security.AdminRole))
    {
        context.Response.StatusCode = StatusCodes.Status401Unauthorized;
        return;
    }
    
    await app.ApplicationServices.GetRequiredService<SwaggerMiddleware>().Invoke(context);
}).RequireAuthorization(Umbraco.Cms.Core.Security.Constants.Security.AdminRole);

方案选择建议

  • 方案一:优先选择,权限隔离清晰,维护简单,适合大多数场景。
  • 方案二:适合希望统一Swagger入口,且内部API无需严格隐藏JSON文档的场景。
  • 方案三:适合内部用户已使用Umbraco后台,无需额外维护独立认证体系的场景。

内容的提问来源于stack exchange,提问作者glenatron

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.17 20:37:02