Аутентификация Swagger в службе приложений Azure

В моей серверной части Azure Mobile .NET я хочу использовать Azure Мобильный сервер .NET Swagger. Я ищу быстрый способ скрыть пользовательский интерфейс swagger от общего доступа? Есть ли способ предоставить доступ только для избранных пользователей?


person piotrbalut    schedule 08.03.2016    source источник


Ответы (1)


Сначала отказ от ответственности: даже если вы защищаете свой пользовательский интерфейс Swagger от публичного использования, вы не защищаете свои API от публичного использования. Вы должны исходить из того, что все знают все ваши маршруты и имеют соответствующие меры безопасности для защиты любых запросов, которые могут поступать.

При этом простого способа сделать это по-прежнему нет. Swashbuckle (компонент, добавляющий Swagger в Web API) добавляет пользовательский HttpMessageHandler к маршруту /swagger/ui (как показано здесь). Если вы посмотрите на конвейер веб-API, вы можете видите, что если вы укажете собственный обработчик, вы можете обойти весь выбор контроллера, фильтры аутентификации и т. д. Вот что здесь происходит.

Некоторые решения:

  1. Используйте настройку приложения для условного вызова ConfigureSwagger(config) только в режимах отладки. Это предотвратит запуск всех /swagger маршрутов в производство. Или вы можете использовать промежуточный слот и добавить его только туда.
  2. Вы можете обернуть 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));
person brettsam    schedule 09.03.2016
comment
если я попытаюсь удалить маршрут swagger_ui через config.Routes.Remove(swagger_ui), я получу следующую ошибку: в System.Web.Http.WebHost.dll возникло исключение типа «System.NotSupportedException», но оно не было обработано пользователем код Дополнительная информация: эта операция не поддерживается «HostedHttpRouteCollection». любая идея, как изменить маршрут? - person pieter_dv; 10.05.2016
comment
Используете ли вы GlobalConfiguration.Configure для настройки веб-API? asp.net/web-api/overview/ расширенный/. Все наши примеры используют OWIN Self-hosting (документы находятся на той же странице, что и предыдущая ссылка), и похоже, что если вы запустите GlobalConfiguration, вы получите другой тип RouteCollection, который не поддерживает Remove. Если это то, чем ты занимаешься, я могу провести расследование еще немного. - person brettsam; 11.05.2016
comment
да, мы используем GlobalConfiguration, но я исправил это, заменив ваш config.Routes.Remove(swagger_ui); с RouteTable.Routes.Remove(RouteTable.Routes[swagger_ui]); и теперь это работает - person pieter_dv; 12.05.2016