Я не получаю флажок области, если тег авторизации не содержит ролей, запрос авторизации Ajax также не отправляет область

ОБНОВЛЕНИЕ 2: если я изменю тег авторизации контроллера с этого

[Authorize]

к этому

[Authorize(Roles = "Read")]

затем я получаю флажок для выбора области, а запрос токена ajax содержит правильную область и успешно завершается. Однако я все еще получаю красный восклицательный знак. Похоже, Swagger или Swashbuckle требует, чтобы роли соответствовали определениям области действия? Можно ли использовать поток приложения без определенных ролей при использовании Swashbuckle? И если да, то как заставить это работать? Должен ли я вручную устанавливать область действия в классе фильтра операций? Если невозможно использовать Swashbuckle без перечисления ролей в теге авторизации, мне нужно знать, как назначать роли клиентов в IdentityServer3.

ОБНОВЛЕНИЕ 3. Если я изменю фильтр операций на что-то подобное, появится область, но после выбора области и нажатия на «Авторизовать» страница просто перезагрузится. Сначала была успешно отправлена ​​авторизация ajax.

public void Apply(Operation operation, SchemaRegistry schemaRegistry, ApiDescription apiDescription)
{

    var scopes = new List<string>() { "Read" };

    if (scopes.Any())
    {
        if (operation.security == null)
            operation.security = new List<IDictionary<string, IEnumerable<string>>>();

        var oAuthRequirements = new Dictionary<string, IEnumerable<string>>
        {
            { "oauth2", scopes }
        };

        operation.security.Add(oAuthRequirements);
    }
}

Исходное сообщение. Я пытаюсь настроить Swashbuckle, чтобы клиенты могли тестировать службу REST, защищенную потоком учетных данных клиента OAuth2. Переключатель никогда не появляется на странице, не так ли? но я вижу красный кружок с восклицательным знаком, говорящий мне, что ресурс не защищен. Я использую пакет Nuget Swashbuckle.Core версии 5.4.0. Ответ здесь Включить поток учетных данных клиента Oauth2 в Swashbuckle, похоже, следует за тем, что Я сделал и использовал класс AssignOAuth2SecurityRequirements дословно. Я не вставлял javascript и не думаю, что должен, поскольку моя схема авторизации довольно стандартна. Когда я удаляю ключевое слово Authorize на контроллере, у этого метода больше нет красного восклицания в пользовательском интерфейсе Swagger, что, как я надеюсь, означает, что я близок, но я не нахожу недостающую ссылку. Поскольку этот поток является «приложением», и у меня есть только одна область, я хотел убедиться, что она выглядит правильно настроенной и clientSecret загружен в нужное место.

ОБНОВЛЕНИЕ 1 Я смог отладить вызов AJAX и вижу, что область действия не задана и поэтому не отправлена ​​в запросе. Почему не устанавливается область действия? Почему у меня нет флажка для выбора области?

Вот мой SwaggerConfig.cs

public class SwaggerConfig
{
    public static void Register()
    {
        var thisAssembly = typeof(SwaggerConfig).Assembly;

        GlobalConfiguration.Configuration
            .EnableSwagger(c =>
            {
                c.SingleApiVersion("v1", "waRougeOneApp");
                c.OAuth2("oauth2")
                    .Description("OAuth2 Client Credentials Grant Flow")
                    .Flow("application")
                    .TokenUrl("https://securitydev.rougeone.com/core/connect/token")
                    .Scopes(scopes =>
                    {
                        scopes.Add("Read", "Read access to protected resources");
                    });
                c.IncludeXmlComments(GetXmlCommentsPath());
                c.UseFullTypeNameInSchemaIds();
                c.DescribeAllEnumsAsStrings();
                c.OperationFilter<AssignOAuth2SecurityRequirements>();
            })
            .EnableSwaggerUi(c =>
            {
                c.EnableOAuth2Support(
                    clientId: "client_id",
                    clientSecret: "client_secret",
                    realm: "swagger-realm",
                    appName: "Swagger UI"
                );
            });
    }

    protected static string GetXmlCommentsPath()
    {
        return System.String.Format(@"{0}bin\\waRougeOne.xml", System.AppDomain.CurrentDomain.BaseDirectory);
    }
}

А класс AssignOAuth2SecurityRequirements -

public class AssignOAuth2SecurityRequirements : IOperationFilter
{
    public void Apply(Operation operation, SchemaRegistry schemaRegistry, ApiDescription apiDescription)
    {
        var authorized = apiDescription.ActionDescriptor.GetCustomAttributes<AuthorizeAttribute>();
        if (!authorized.Any()) return;

        if (operation.security == null)
            operation.security = new List<IDictionary<string, IEnumerable<string>>>();

        var oAuthRequirements = new Dictionary<string, IEnumerable<string>>
  {
      {"oauth2", Enumerable.Empty<string>()}
  };

        operation.security.Add(oAuthRequirements);
    }
}

Я безуспешно пытался найти рабочий пример с потоком учетных данных клиента, поэтому я не уверен на 100%, что увижу кнопку переключения, когда все работает правильно. В примерах для неявного потока, если вы наведете курсор на красный восклицательный круг, вы увидите перечисленные типы грантов, щелчок по красному восклицательному кругу покажет варианты для перечисленных областей, в которых вы выбираете один, а затем нажимаете авторизовать, и он возвращается с синий восклицательный знак.

У меня никогда не было флажка для выбора области действия, но я определил только одну область. Что я делаю неправильно? Я обнаружил это при отладке swagger ui JavaScript, который, кажется, указывает на наличие всех необходимых данных?

authorizations
:
null
auths
:
Array[1]
0
:
Object
name
:
"oauth2"
type
:
"oauth2"
value
:
Object
description
:
"OAuth2 Client Credentials Grant Flow"
flow
:
"application"
scopes
:
Object
Read
:
"Read access to protected resources"
__proto__
:
Object
tokenUrl
:
"https://security.starrwarrs.com/core/connect/token"
type
:
"oauth2"
__proto__
:
Object
__proto__
:
Object
length
:
1
__proto__
:
Array[0]

person user2197446    schedule 27.09.2016    source источник
comment
Вы не должны редактировать ответ на свой вопрос. Если вы придумали решение своей проблемы, которым вы хотели бы поделиться, вы должны опубликовать его в качестве ответа.   -  person Servy    schedule 29.09.2016


Ответы (2)


Решение !! Труднее всего было понять последнюю часть, которую я, наконец, сделал с помощью инструментов разработчика Chrome, которые показали маленький красный крестик на сетевом теге, показывающий следующее сообщение об ошибке:

XMLHttpRequest cannot load http://security.RogueOne.com/core/connect/token. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:62561' is therefore not allowed access.

Сообщение об ошибке, наконец, соединяет точки ниже, до тех пор, пока не будет вызываться полная функция JavaScript на OAuthComplete, но без токена. На вкладке сети отображается «Этот запрос не имеет доступных данных ответа», но я бы увидел Content-Length в заголовках ответа с типом содержимого Json. Fiddler также показал ответ, который выглядел (и был) правильно сформированным JSON.

Я описал эту ошибку здесь Swagger UI not parsing response, что было связано с тем, что IdentityServer3 правильно не добавлял заголовок ответа «Access-Control-Allow-Origin: http://localhost:62561 "Вы можете заставить IdentityServer3 отправить этот заголовок, обновив создание клиента следующим образом:

new Client
{
    ClientName = "SwaggerUI",
    Enabled = true,
    ClientId = "swaggerUI",
    ClientSecrets = new List<Secret>
    {
        new Secret("PasswordGoesHere".Sha256())
    },
    Flow = Flows.ClientCredentials,
    AllowClientCredentialsOnly = true,
    AllowedScopes = new List<string>
    {
        "Read"
    },

    Claims = new List<Claim>
    {
        new Claim("client_type", "headless"),
        new Claim("client_owner", "Portal"),
        new Claim("app_detail", "allow")
    },
    PrefixClientClaims = false
    // Add the AllowedCorOrigins to get the Access-Control-Allow-Origin header to be inserted for the following domains
    ,AllowedCorsOrigins = new List<string>
    {
        "http://localhost:62561/"
        ,"http://portaldev.RogueOne.com"
        ,"https://portaldev.RogueOne.com"
    }
}    

AllowedCorsOrigins был последним кусочком моей головоломки. Надеюсь, это поможет кому-то еще, кто сталкивается с той же проблемой.

person user2197446    schedule 11.10.2016

Вот шаги, которые мы сделали и работали:

  1. В файле SwaggerConfig добавьте следующие настройки:
c.OAuth2("oauth2")
 .Description("OAuth2 Implicit Grant") 
 .Flow("implicit")
 .AuthorizationUrl(swaggerConfigurations["IssuerUri"].ToString())
 .Scopes(scopes =>
  {
    scopes.Add("user_scope", "Access REST API");
  });

Атрибуты:

  • Название схемы авторизации (oauth2 в приведенном выше примере)
  • Описание схемы авторизации
  • Поток - Тип используемого гранта
  • URL-адрес авторизации - должен быть URL-адресом авторизации URL-адреса системы управления идентификацией (например: https://auth2.test.com/oauth2/authorize)
  • Области - имя области

II. В файле SwaggerConfig добавьте следующие настройки также в разделе конфигурации пользовательского интерфейса swagger:

c.EnableOAuth2Support(swaggerConfigurations["ClientId"].ToString(), string.Empty, swaggerConfigurations["RedirectUri"].ToString(), "Swagger", " ", new Dictionary<string, string> { { "resource", GetResources() } });

Метод принимает следующие параметры:

  • clientId - это должен быть идентификатор клиента для swagger, настроенный в Security Token Service.
  • clientSecret - это должен быть секретный ключ клиента. Это требуется только в случае типа предоставления кода.
  • область - это должен быть URL-адрес перенаправления (это должен быть [базовый адрес] + swagger / ui / o2c-html)
  • appName - это должно быть чванство
  • scopeSeperator - это не требуется для передачи, если есть только область
  • additionalQueryStringParams - должен содержать список допустимых аудиторий, соответствующий ресурсу, для которого выпущен токен.

III. Создайте новый фильтр операций в проекте веб-API, как показано ниже:

public class CustomOperationFilter : IOperationFilter
    {              
        public void Apply(Operation operation, SchemaRegistry schemaRegistry, ApiDescription apiDescription)
        {     
            string clientId = "clientID";
            if (apiDescription != null)
            {
                var actFilters = apiDescription.ActionDescriptor.GetFilterPipeline();

                var allowsAnonymous = actFilters.Select(f => f.Instance).OfType<OverrideAuthorizationAttribute>().Any();
                if (allowsAnonymous)
                {
                    return; // must be an anonymous method
                }
            }

            if (operation != null)
            {
                if (operation.security == null)
                {
                    operation.security = new List<IDictionary<string, IEnumerable<string>>>();
                }

                var authRequirements = new Dictionary<string, IEnumerable<string>>
                {
                    { "oauth2", new List<string> { clientId } }
                };

                operation.security.Add(authRequirements);
            }
        }
    }

Этот класс будет использоваться для привязки областей действия OAuth к отдельным операциям.

IV. Добавьте указанный выше фильтр в файл конфигурации swagger (см. Код ниже)

c.OperationFilter<CustomOperationFilter>();

V. Настройте идентификатор клиента, секрет, URL-адрес перенаправления и ресурс в службе токенов безопасности

VI. Если в проекте веб-API используется index.html для внедрения определенных полей / стилей пользовательского интерфейса API, убедитесь, что весь код javascript не поврежден с версией Swashbuckle файла index.html (как указано в местоположение - https://github.com/domaindrivendev/Swashbuckle/blob/master/Swashbuckle.Core/SwaggerUi/CustomAssets/index.html)

person Silly John    schedule 28.09.2016
comment
На данный момент я думаю, что мне нужно либо указать роли в теге авторизации на контроллере, либо OperationFilter необходимо принудительно установить область чтения. Я не уверен, сработает ли какая-либо идея или какой вариант будет правильным. - person user2197446; 28.09.2016