当授权标签不包含角色时,我没有获得范围复选框,Ajax 授权请求也不发送范围

I'm not getting a scope checkbox when the Authorize tag doesn't contain roles, Ajax authorization request not sending scope either

更新 2: 如果我从这个更改我的控制器授权标签

[Authorize]

至此

[Authorize(Roles = "Read")]

然后我得到范围 selection 的复选框,并且 ajax 令牌请求包含正确的范围并成功完成。但是,我仍然以红色感叹号结束。 看起来 Swagger 或 Swashbuckle 需要ui角色匹配范围定义?使用 Swashbuckle 时是否可以使用未定义角色的应用程序流程?如果是这样,你如何让它工作? 我是否必须在操作过滤器中手动设置范围 class?如果不在授权标签中列出角色就无法使用 Swashbuckle,那么我需要知道如何在 IdentityServer3 中分配客户端角色。

更新 3 如果我将操作过滤器更改为类似这样的范围,则会出现范围,但在 select 范围并单击授权后,页面会重新加载。 ajax 授权首先发送成功。 这样比较近了,但是授权还是不stick(这里不知道用什么词,但是stick好像可以概括一下。)如何获得stick的授权?

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);
    }
}

原创Post 我正在尝试配置 Swashbuckle 以允许客户端测试受 OAuth2 客户端凭据流保护的 REST 服务。 开关从未出现在页面上,对吗?,但我确实看到一个带有感叹号的红色圆圈,告诉我资源未受保护。我正在使用 nuget 包 Swashbuckle.Core 版本 5.4.0。这里的答案 似乎遵循了我所做的,并且逐字使用了 AssignOAuth2SecurityRequirements class。我没有注入任何 javascript 并且不相信我必须这样做,因为我的授权方案是相当标准的。当我删除控制器上的 Authorize 关键字时,该方法在 Swagger UI 中不再有红色感叹号,我希望这意味着我很接近,但我没有找到丢失的 link .由于这个 Flow 是 "application" 而我只有一个范围,所以我想确保它看起来配置正确并且 clientSecret 加载到正确的位置。

更新 1 我已经能够调试 AJAX 调用,并且可以看到范围未设置,因此未在请求中发送。 为什么没有设置范围?为什么我没有 select 范围的复选框?

这是我的 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);
    }
}

并且 AssignOAuth2SecurityRequi备注 class 是

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% 确定当一切正常工作时我会看到一个切换按钮。在隐式流程的示例中,如果您将鼠标悬停在红色感叹号圆圈上,您会看到列出的授权类型,单击红色感叹号圆圈会显示列出的范围选项,您可以在其中 select 一个,然后单击授权,它回来时发出蓝色的感叹。

对我来说,我从来没有select一个范围的复选框,但我只定义了一个范围。我究竟做错了什么?我在调试 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]

这些是我们已经完成和工作的步骤:

  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)
  • Scopes – 作用域名称

二.在 SwaggerConfig 文件中,也在 swagger ui 配置部分下添加以下设置:

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

该方法接受以下参数:

  • clientId – 这应该是在安全令牌服务中配置的 swagger 的客户端 ID
  • clientSecret – 这应该是客户端密钥。仅在代码授予类型
  • 的情况下才需要 ui 红色
  • realm – 这应该是重定向 url(这应该是 [base address] + swagger/ui/o2c-html)
  • appName – 这应该是 swagger
  • scopeSeperator – 如果只有 scope
  • ,则不需要传递 uired
  • additionalQueryStringParams – 这应该有有效受众的列表,这对应于为其颁发令牌的资源。

三。在web api项目中新建一个Operation Filter如下图:

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);
            }
        }
    }

此 class 将用于将 OAuth 范围绑定到各个操作

四.在 swagger 配置文件中添加上面的过滤器(见下面的代码)

c.OperationFilter<CustomOperationFilter>();

伏。在安全令牌服务

中配置客户端 ID、密码、重定向 Url 和资源

六。在 Web API 项目中,如果有一个 index.html 被用来注入 API 特定的 UI fields/styles,那么请确保所有 javascript 代码与 index.html 文件的 Swashbuckle 版本保持完整(如位置 - https://github.com/domaindrivendev/Swashbuckle/blob/master/Swashbuckle.Core/SwaggerUi/CustomAssets/index.html 中提供)

解决方法!! 最后一部分是最难弄清楚的,我最终在 Chrome 开发人员工具的帮助下完成了,该工具在网络标记上显示了一个红色的 X,并显示以下错误消息:

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.

错误消息最终连接了下面的点,直到那时 OAuthComplete 完成 JavaScript 函数将被调用,但没有令牌。网络选项卡显示 "This request has no response data available",但我会在响应 header 中看到 Content-Length,content-type 为 Json。 Fiddler 还显示了看起来(并且)格式正确的响应 JSON.

我在此处描述了这个错误 Swagger UI not parsing reponse which was due to IdentityServer3 correctly not adding a response header of "Access-Control-Allow-Origin:http://localhost:62561“您可以强制 IdentityServer3 发送该错误 header,方法是将您的客户端创建更新为以下内容:

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 是我的最后一块拼图。希望这可以帮助面临同样问题的其他人