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

时间:2016-09-27 15:54:15

标签: c# oauth-2.0 swagger swashbuckle

更新2:如果我从此处更改我的控制器授权标记

[Authorize]

到这个

[Authorize(Roles = "Read")]

然后我得到范围选择的复选框,ajax令牌请求包含正确的范围并成功完成。然而,我仍然以红色感叹号结束。 看起来Swagger或Swashbuckle要求角色与范围定义匹配?使用Swashbuckle时是否可以使用没有定义角色的应用程序流?如果是这样,你怎么做到这一点?我是否必须在操作过滤器类中手动设置范围?如果在Authorize标签中没有列出Roles的情况下无法使用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以允许客户端测试受OAuth2客户端凭据流保护的REST服务。 切换页面上永远不会出现切换,是吗?,但我确实得到一个带有感叹号的红色圆圈,告诉我资源没有受到保护。我正在使用nuget包Swashbuckle.Core版本5.4.0。这里的答案Enable Oauth2 client credentials flow in Swashbuckle似乎遵循我所做的,并逐字使用了AssignOAuth2SecurityRequirements类。我没有注入任何JavaScript,并且不相信我必须,因为我的授权方案是相当标准的。当我删除Controller上的授权关键字时,该方法在Swagger UI中不再有红色感叹号,我希望这意味着我很接近,但我找不到丢失的链接。由于这个Flow是“应用程序”而我只有一个作用域,我想确保它看起来配置正确并且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]

2 个答案:

答案 0 :(得分:1)

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

  1. 在SwaggerConfig文件中,添加以下设置:
  2. c.OAuth2("oauth2")
     .Description("OAuth2 Implicit Grant") 
     .Flow("implicit")
     .AuthorizationUrl(swaggerConfigurations["IssuerUri"].ToString())
     .Scopes(scopes =>
      {
        scopes.Add("user_impersonation", "Access REST API");
      });
    

    属性是:

    • 授权方案的名称(上例中的oauth2)
    • 授权方案说明
    • 流量 - 拨款类型
    • 授权网址 - 应该是STS网址(例如: https://auth2.test.com/oauth2/authorize
    • 范围 - 范围名称

    II。在SwaggerConfig文件中,还可以在swagger ui配置部分下添加以下设置:

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

    该方法接受以下参数:

    • clientId - 这应该是安全令牌服务中配置的swagger的客户端ID
    • clientSecret - 这应该是客户端密钥。仅在代码授予类型
    • 的情况下才需要这样做
    • 领域 - 这应该是重定向网址(这应该是[基地址] + swagger / ui / o2c-html)
    • appName - 这应该是招摇
    • scopeSeperator - 如果只有范围
    • ,则不需要传递
    • additionalQueryStringParams - 这应该包含有效受众列表,这对应于为其颁发令牌的资源。

    III。在web api项目中创建一个新的Operation Filter,如下所示:

    public class AssignOperationFilters : 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<AssignOperationFilters>();
    

    诉在安全令牌服务中配置客户端ID,密钥,重定向URL和资源

    VI。在Web API项目中,如果有一个index.html用于注入特定于API的UI字段/样式,那么请确保所有的javascript代码都保留在原始版本的index.html文件的Swashbuckle中(如location - https://github.com/domaindrivendev/Swashbuckle/blob/master/Swashbuckle.Core/SwaggerUi/CustomAssets/index.html

答案 1 :(得分:1)

<强>解决方案!! 最后一部分是最难以弄清楚的,我最终在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.

错误消息最终连接了下面的点,直到那时将调用on OAuthComplete完整的JavaScript函数,但没有令牌。网络选项卡显示&#34;此请求没有可用的响应数据&#34;,但我在响应标头中看到内容类型为Json的Content-Length。 Fiddler还展示了看起来像(并且是)JSON的反应。

我在这里描述了这个错误Swagger UI not parsing reponse,这是由于IdentityServer3正确地没有添加&#34; Access-Control-Allow-Origin:http://localhost:62561&#34;的响应头。您可以通过将客户端创建更新为以下内容来强制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是我拼图的最后一块。希望这可以帮助面临同样问题的其他人