Azure 应用服务中的 Swagger 身份验证
Swagger authentication in Azure App Service
在我的 Azure Mobile .NET 后端中,我想使用 Azure Mobile .NET Server Swagger 。我正在寻找从 public 访问中隐藏 swagger UI 的快速方法?有没有办法只为选定的用户提供访问权限?
首先是免责声明:即使您保护您的 Swagger UI 免受 public 消耗,您也没有保护您的 API 免受 public 消耗。您必须假设每个人都知道您的所有路由,并有适当的安全措施来保护可能进入的任何请求。
话虽这么说,但仍然没有一种简单的方法可以做到这一点。 Swashbuckle (the piece that adds Swagger to Web API) adds a custom HttpMessageHandler
to the /swagger/ui
route (as seen here). If you look at the Web API pipeline,你可以看到,如果你指定一个自定义处理程序,你可以绕过所有的控制器选择,Auth 过滤器等。这就是这里发生的事情。
一些解决方案:
- 使用应用设置仅在调试模式下有条件地调用
ConfigureSwagger(config)
。这将阻止所有 /swagger
路由投入生产。或者您可以使用暂存槽并仅将其添加到那里。
- 你可以用这样的东西包裹
SwaggerUiHandler
Basic Auth MessageHandler。如果用户转到 /swagger/ui
路线,这将提示用户输入基本信用。请参阅下面我对此代码的修改版本。
也许再考虑一下我们可以想出一个更好的解决方案——我在 Swashbuckle 存储库中看到了几个问题 (here and here),表明您不是第一个遇到这个问题的人.
修改后的 BasicAuthHandler(来自 here):
警告:最低限度测试(并确保更改验证方式 user/pass)
public class BasicAuthMessageHandler : DelegatingHandler
{
private const string BasicAuthResponseHeader = "WWW-Authenticate";
private const string BasicAuthResponseHeaderValue = "Basic";
public BasicAuthMessageHandler(HttpMessageHandler innerHandler)
{
this.InnerHandler = innerHandler;
}
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
AuthenticationHeaderValue authValue = request.Headers.Authorization;
HttpResponseMessage unauthorizedResponse = request.CreateUnauthorizedResponse();
if (authValue != null && !string.IsNullOrWhiteSpace(authValue.Parameter))
{
Credentials parsedCredentials = ParseAuthorizationHeader(authValue.Parameter);
if (parsedCredentials != null)
{
// TODO: Check that the user/pass are valid
if (parsedCredentials.Username == "user" &&
parsedCredentials.Password == "pass")
{
// If match, pass along to the inner handler
return base.SendAsync(request, cancellationToken);
}
}
}
else
{
// Prompt for creds
unauthorizedResponse.Headers.Add(BasicAuthResponseHeader, BasicAuthResponseHeaderValue);
}
return Task.FromResult(unauthorizedResponse);
}
private Credentials ParseAuthorizationHeader(string authHeader)
{
string[] credentials = Encoding.ASCII.GetString(Convert
.FromBase64String(authHeader))
.Split(
new[] { ':' });
if (credentials.Length != 2 || string.IsNullOrEmpty(credentials[0])
|| string.IsNullOrEmpty(credentials[1])) return null;
return new Credentials()
{
Username = credentials[0],
Password = credentials[1],
};
}
}
正在注册 Swagger 路由
// Do this after calling ConfigureSwagger
ConfigureSwagger(config);
// Remove the swagger_ui route and re-add it with the wrapped handler.
var route = config.Routes["swagger_ui"];
config.Routes.Remove("swagger_ui");
config.Routes.MapHttpRoute("swagger_ui", route.RouteTemplate, route.Defaults, route.Constraints, new BasicAuthMessageHandler(route.Handler));
在我的 Azure Mobile .NET 后端中,我想使用 Azure Mobile .NET Server Swagger 。我正在寻找从 public 访问中隐藏 swagger UI 的快速方法?有没有办法只为选定的用户提供访问权限?
首先是免责声明:即使您保护您的 Swagger UI 免受 public 消耗,您也没有保护您的 API 免受 public 消耗。您必须假设每个人都知道您的所有路由,并有适当的安全措施来保护可能进入的任何请求。
话虽这么说,但仍然没有一种简单的方法可以做到这一点。 Swashbuckle (the piece that adds Swagger to Web API) adds a custom HttpMessageHandler
to the /swagger/ui
route (as seen here). If you look at the Web API pipeline,你可以看到,如果你指定一个自定义处理程序,你可以绕过所有的控制器选择,Auth 过滤器等。这就是这里发生的事情。
一些解决方案:
- 使用应用设置仅在调试模式下有条件地调用
ConfigureSwagger(config)
。这将阻止所有/swagger
路由投入生产。或者您可以使用暂存槽并仅将其添加到那里。 - 你可以用这样的东西包裹
SwaggerUiHandler
Basic Auth MessageHandler。如果用户转到/swagger/ui
路线,这将提示用户输入基本信用。请参阅下面我对此代码的修改版本。
也许再考虑一下我们可以想出一个更好的解决方案——我在 Swashbuckle 存储库中看到了几个问题 (here and here),表明您不是第一个遇到这个问题的人.
修改后的 BasicAuthHandler(来自 here):
警告:最低限度测试(并确保更改验证方式 user/pass)
public class BasicAuthMessageHandler : DelegatingHandler
{
private const string BasicAuthResponseHeader = "WWW-Authenticate";
private const string BasicAuthResponseHeaderValue = "Basic";
public BasicAuthMessageHandler(HttpMessageHandler innerHandler)
{
this.InnerHandler = innerHandler;
}
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
AuthenticationHeaderValue authValue = request.Headers.Authorization;
HttpResponseMessage unauthorizedResponse = request.CreateUnauthorizedResponse();
if (authValue != null && !string.IsNullOrWhiteSpace(authValue.Parameter))
{
Credentials parsedCredentials = ParseAuthorizationHeader(authValue.Parameter);
if (parsedCredentials != null)
{
// TODO: Check that the user/pass are valid
if (parsedCredentials.Username == "user" &&
parsedCredentials.Password == "pass")
{
// If match, pass along to the inner handler
return base.SendAsync(request, cancellationToken);
}
}
}
else
{
// Prompt for creds
unauthorizedResponse.Headers.Add(BasicAuthResponseHeader, BasicAuthResponseHeaderValue);
}
return Task.FromResult(unauthorizedResponse);
}
private Credentials ParseAuthorizationHeader(string authHeader)
{
string[] credentials = Encoding.ASCII.GetString(Convert
.FromBase64String(authHeader))
.Split(
new[] { ':' });
if (credentials.Length != 2 || string.IsNullOrEmpty(credentials[0])
|| string.IsNullOrEmpty(credentials[1])) return null;
return new Credentials()
{
Username = credentials[0],
Password = credentials[1],
};
}
}
正在注册 Swagger 路由
// Do this after calling ConfigureSwagger
ConfigureSwagger(config);
// Remove the swagger_ui route and re-add it with the wrapped handler.
var route = config.Routes["swagger_ui"];
config.Routes.Remove("swagger_ui");
config.Routes.MapHttpRoute("swagger_ui", route.RouteTemplate, route.Defaults, route.Constraints, new BasicAuthMessageHandler(route.Handler));