.NET 8中如何保护swagger/1.0/swagger.json端点?
如何在.NET 8中保护Swagger JSON端点
我在ReactJS应用中创建了自定义SwaggerUI(index.html)文件,可通过myapplication.com/docs/swagger/index.html访问。由于该路由经过/docs/路径,已应用STS认证。但SwaggerUI从/swagger/v1/swagger.json端点获取数据,当前该端点未受保护,任何人都可通过myapplication.com/swagger/v1/swagger.json访问它。请问如何在.NET 8中保护这个端点?
ReactJS代码
App.tsx
import React, { useState } from 'react' import SwaggerUI from 'swagger-ui-react' import 'swagger-ui-react/swagger-ui.css' import { GettingStartedSection } from 'sections/getting-started' const App = () => { const [activeItem, setActiveItem] = useState<string | undefined>('getting-started') return ( <CustomPageWrapper> <div id="App" className="App"> <DocumentationWrapper> <GettingStartedSection /> <SwaggerUI layout="BaseLayout" url="/v1/swagger/1.0/swagger.json" /> <HandlingErrorsAndVersioningSection /> </DocumentationWrapper> </div> </CustomPageWrapper> ) } export default App
root-app.tsx
import React from 'react' import { Route, BrowserRouter, Switch } from 'react-router-dom' import { AuthContextProvider } from './contexts/auth.context' import { AuthzContextProvider } from './contexts/authz.context' import { UserContextProvider } from './contexts/user' import { AuthCallbackPage, LogoutCallbackPage, LogoutPage, SilentRenewPage } from './pages/auth' import { AuthorizedRoute } from './routes/authorized-route' import App from './App' const RootApp = () => { const returnEmptyComponent = () => <></> return ( <AuthContextProvider> <AuthzContextProvider> <BrowserRouter> <UserContextProvider> <Switch> <Route path="/docs/auth/callback" component={AuthCallbackPage} /> <Route path="/docs/auth/silent-renew" component={SilentRenewPage} /> <Route exact path="/account/logout" component={LogoutPage} /> <Route exact path="/docs/auth/logout/callback" component={LogoutCallbackPage} /> <AuthorizedRoute path="/*" component={App} /> </Switch> </UserContextProvider> </BrowserRouter> </AuthzContextProvider> </AuthContextProvider> ) } export default RootApp
C#代码
app.UseSwagger(); app.UseSwaggerUI(options => { // build a swagger endpoint for each discovered API version bool isPathPrefixDefined = !string.IsNullOrWhiteSpace(swaggerOptions?.PathPrefix); if (isPathPrefixDefined) { foreach (var description in provider.ApiVersionDescriptions) { options.SwaggerEndpoint($"{swaggerOptions.PathPrefix}/swagger/{description.GroupName}/swagger.json", $"{swaggerOptions.GeneratedJsonName} {description.GroupName.ToUpperInvariant()}"); } } else { foreach (var description in provider.ApiVersionDescriptions) { options.SwaggerEndpoint($"/swagger/{description.GroupName}/swagger.json", description.GroupName.ToUpperInvariant()); } } if (swaggerOptions.IncludeAuthentication) { options.OAuthClientId(swaggerOptions.SecurityDefinition.ClientId); options.OAuthClientSecret(swaggerOptions.SecurityDefinition.ClientSecret); } });
解决方案
方法1:为Swagger JSON端点添加授权中间件
在.NET 8的管道中,在UseSwagger()之后添加授权规则,限制只有通过STS认证的用户才能访问/swagger/*路径:
// 先配置授权服务(如果还没配置) builder.Services.AddAuthorization(options => { options.AddPolicy("SwaggerAccess", policy => { // 要求用户已通过STS认证 policy.RequireAuthenticatedUser(); // 如果需要特定角色或权限,可添加以下规则 // policy.RequireRole("Admin"); // policy.RequireClaim("scope", "api.read"); }); }); // 在UseSwagger之后添加授权中间件 app.UseSwagger(); // 为Swagger JSON端点应用授权策略 app.MapWhen(context => context.Request.Path.StartsWithSegments("/swagger"), appBuilder => { appBuilder.UseAuthorization(); appBuilder.Use(async (context, next) => { var result = await context.AuthenticateAsync(); if (!result.Succeeded) { context.Response.StatusCode = StatusCodes.Status401Unauthorized; return; } var authorizationResult = await context.AuthorizeAsync("SwaggerAccess"); if (!authorizationResult.Succeeded) { context.Response.StatusCode = StatusCodes.Status403Forbidden; return; } await next(); }); }); app.UseSwaggerUI(...); // 保持原有SwaggerUI配置
方法2:将Swagger JSON端点迁移到/docs/路径下
既然你的SwaggerUI已经在/docs/路径下受保护,可以把Swagger JSON的路径也调整到/docs/前缀下,这样就能复用现有的STS认证规则:
- 修改Swagger配置,设置PathPrefix为
/docs:
// 假设swaggerOptions是你的配置对象,设置PathPrefix swaggerOptions.PathPrefix = "/docs"; app.UseSwagger(options => { // 设置Swagger JSON的路径前缀 options.RouteTemplate = "docs/swagger/{documentName}/swagger.json"; }); app.UseSwaggerUI(options => { bool isPathPrefixDefined = !string.IsNullOrWhiteSpace(swaggerOptions?.PathPrefix); foreach (var description in provider.ApiVersionDescriptions) { options.SwaggerEndpoint($"/docs/swagger/{description.GroupName}/swagger.json", $"{swaggerOptions.GeneratedJsonName} {description.GroupName.ToUpperInvariant()}"); } // 保持原有OAuth配置 if (swaggerOptions.IncludeAuthentication) { options.OAuthClientId(swaggerOptions.SecurityDefinition.ClientId); options.OAuthClientSecret(swaggerOptions.SecurityDefinition.ClientSecret); } });
- 修改React代码中的SwaggerUI url,匹配新的路径:
<SwaggerUI layout="BaseLayout" url="/docs/swagger/1.0/swagger.json" />
这样Swagger JSON的路径就变成了myapplication.com/docs/swagger/1.0/swagger.json,会自动继承/docs/路径下的STS认证保护,无需额外配置授权规则。
方法3:使用端点路由直接保护Swagger JSON
在.NET 8中,也可以直接通过端点路由来保护Swagger的JSON端点:
app.UseSwagger(); // 保护Swagger JSON端点 app.MapGet("/swagger/{documentName}/swagger.json", async context => { var result = await context.AuthenticateAsync(); if (!result.Succeeded) { context.Response.StatusCode = StatusCodes.Status401Unauthorized; return; } // 如果需要权限验证,添加授权检查 var authResult = await context.AuthorizeAsync("SwaggerAccess"); if (!authResult.Succeeded) { context.Response.StatusCode = StatusCodes.Status403Forbidden; return; } // 转发请求到原始Swagger中间件 await app.ApplicationServices.CreateScope().ServiceProvider .GetRequiredService<SwaggerMiddleware>() .Invoke(context); }).RequireAuthorization("SwaggerAccess"); app.UseSwaggerUI(...);
内容的提问来源于stack exchange,提问作者Mariselvam
相关产品推荐
相关产品推荐

