В моей серверной части Azure Mobile .NET я хочу использовать Azure Мобильный сервер .NET Swagger. Я ищу быстрый способ скрыть пользовательский интерфейс swagger от общего доступа? Есть ли способ предоставить доступ только для избранных пользователей?
Аутентификация Swagger в службе приложений Azure
Ответы (1)
Сначала отказ от ответственности: даже если вы защищаете свой пользовательский интерфейс Swagger от публичного использования, вы не защищаете свои API от публичного использования. Вы должны исходить из того, что все знают все ваши маршруты и имеют соответствующие меры безопасности для защиты любых запросов, которые могут поступать.
При этом простого способа сделать это по-прежнему нет. Swashbuckle (компонент, добавляющий Swagger в Web API) добавляет пользовательский HttpMessageHandler
к маршруту /swagger/ui
(как показано здесь). Если вы посмотрите на конвейер веб-API, вы можете видите, что если вы укажете собственный обработчик, вы можете обойти весь выбор контроллера, фильтры аутентификации и т. д. Вот что здесь происходит.
Некоторые решения:
- Используйте настройку приложения для условного вызова
ConfigureSwagger(config)
только в режимах отладки. Это предотвратит запуск всех/swagger
маршрутов в производство. Или вы можете использовать промежуточный слот и добавить его только туда. - Вы можете обернуть
SwaggerUiHandler
чем-то вроде этого Базовый обработчик сообщений аутентификации. Это запросит у пользователя базовые кредиты, если они пойдут по маршруту/swagger/ui
. См. ниже мою модифицированную версию этого кода.
Возможно, немного подумав, мы сможем найти лучшее решение — я вижу пару проблем (здесь и здесь) в репозитории Swashbuckle, которые указывают, что вы не первый, кто попал в это.
Измененный BasicAuthHandler (из здесь< /а>):
Внимание: минимальное тестирование (и обязательно измените способ подтверждения пользователя/пароля)
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));