【问题标题】:I'm not getting a scope checkbox when the Authorize tag doesn't contain roles, Ajax authorization request not sending scope either当授权标签不包含角色时,我没有得到范围复选框,Ajax 授权请求也不发送范围
【发布时间】:2017-02-05 08:27:47
【问题描述】:

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

[Authorize]

到这里

[Authorize(Roles = "Read")]

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

更新 3 如果我将操作过滤器更改为类似的内容,则会出现范围,但在选择范围并单击授权后,页面会重新加载。 ajax授权先发送成功。 这个比较接近了,但是授权还是不粘(这里不知道用什么词,但是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);
    }
}

原帖 我正在尝试配置 Swashbuckle 以允许客户端测试受 OAuth2 客户端凭据流保护的 REST 服务。 切换永远不会出现在页面上,不是吗?,但我确实看到了一个带有感叹号的红色圆圈,告诉我资源不受保护。我正在使用 nuget 包 Swashbuckle.Core 版本 5.4.0。 Enable Oauth2 client credentials flow in Swashbuckle 这里的答案似乎遵循我所做的,并且逐字使用了 AssignOAuth2SecurityRequirements 类。我没有注入任何 javascript 并且不相信我必须这样做,因为我的授权方案是相当标准的。当我删除控制器上的 Authorize 关键字时,该方法在 Swagger UI 中不再有红色感叹号,我希望这意味着我已经接近了,但我没有找到丢失的链接。由于此流程是“应用程序”并且我只有一个范围,因此我想确保它看起来配置正确并且 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]

【问题讨论】:

  • 您不应该编辑问题的答案。如果您想出解决问题的方法并想分享,您应该将其发布为答案。

标签: c# oauth-2.0 swagger swashbuckle


【解决方案1】:

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

  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)
  • 授权方案说明
  • Flow – 授权类型 要使用的
  • Authorization Url – 应该是身份管理系统 url 的 Auth Url(例如: https://auth2.test.com/oauth2/authorize)
  • 范围 - 范围名称

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

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

该方法接受以下参数:

  • clientId - 这应该是安全令牌服务中配置的 swagger 的客户端 ID
  • clientSecret – 这应该是客户端密钥。只有在代码授权类型的情况下才需要这样做
  • realm – 这应该是重定向 url(这应该是 [base address] + swagger/ui/o2c-html)
  • appName - 这应该是大摇大摆的
  • scopeSeparator – 如果只有范围,则不需要传递
  • 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);
            }
        }
    }

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

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

c.OperationFilter<CustomOperationFilter>();

V。在 Security Token Service 中配置 Client ID、Secret、Redirect Url 和 Resource

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

【讨论】:

  • 此时我认为我要么必须在控制器上的 Authorize 标记中列出角色,要么 OperationFilter 需要强制“读取”范围。我不确定这两个想法是否可行,或者正确的选择是什么。
【解决方案2】:

解决方案!! 最后一部分是最难弄清楚的,我终于在 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 函数将被调用,但没有令牌。网络选项卡显示“此请求没有可用的响应数据”,但我会在响应标头中看到 Content-Length,其内容类型为 Json。 Fiddler 还显示了看起来像(并且是)格式良好的 JSON 的响应。

我在Swagger UI not parsing reponse 描述了这个错误,这是由于 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 是我拼图的最后一块。希望这可以帮助面临同样问题的其他人

【讨论】:

    猜你喜欢
    • 2022-08-19
    • 1970-01-01
    • 1970-01-01
    • 2020-07-19
    • 2020-09-20
    • 2016-06-27
    • 2018-05-26
    • 2021-07-24
    • 2020-03-28
    相关资源
    最近更新 更多