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

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

[Authorize] 

对此

 [Authorize(Roles = "Read")] 

然后我得到范围选择的复选框,ajax令牌请求包含正确的范围并成功完成。 然而,我仍然以红色感叹号结束。 看起来Swagger或Swashbuckle要求角色与范围定义匹配? 使用Swashbuckle时是否可以使用没有定义角色的应用程序流程? 如果是这样,你怎么做到这一点? 我是否必须在操作filter类中手动设置范围? 如果在Authorize标记中没有列出Roles就无法使用Swashbuckle,那么我需要知道如何在IdentityServer3中分配客户端角色。

更新3如果我将操作filter更改为类似的范围,则会显示范围,但在选择范围并单击“授权”后,页面将重新加载。 首先成功发送了ajax授权。 这是更接近,但授权仍然没有坚持(不知道在这里使用什么术语,但坚持似乎总结了。)我如何获得授权坚持?

 public void Apply(Operation operation, SchemaRegistry schemaRegistry, ApiDescription apiDescription) { var scopes = new List() { "Read" }; if (scopes.Any()) { if (operation.security == null) operation.security = new List<IDictionary<string, IEnumerable>>(); var oAuthRequirements = new Dictionary<string, IEnumerable> { { "oauth2", scopes } }; operation.security.Add(oAuthRequirements); } } 

原始post我正在尝试配置Swashbuckle以允许客户端测试受OAuth2客户端凭据流保护的REST服务。 切换永远不会出现在页面上,不是吗? ,但我确实得到一个带有感叹号的红色圆圈,告诉我资源没有受到保护。 我正在使用nuget包Swashbuckle.Core版本5.4.0。 这里的答案在Swashbuckle中启用Oauth2客户端凭据流似乎遵循我所做的,并逐字使用了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(); }) .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(); if (!authorized.Any()) return; if (operation.security == null) operation.security = new List<IDictionary<string, IEnumerable>>(); var oAuthRequirements = new Dictionary<string, IEnumerable> { {"oauth2", Enumerable.Empty()} }; operation.security.Add(oAuthRequirements); } } 

我一直试图找到一个客户端凭据流程的工作示例,但没有成功,所以我不能100%确定当一切正常时我会看到一个切换按钮。 在隐藏流程的示例中,如果将鼠标hover在红色感叹圈上,则会看到列出的授权类型,单击红色感叹号圆圈会显示列出的范围选项,您可以在其中选择一个,然后单击授权,然后返回蓝色感叹号。

对我来说,我从来没有选中一个范围的复选框,但我只定义了一个范围。 我究竟做错了什么? 我在调试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_impersonation", "Access REST API"); }); 

属性是:

  • 授权方案的名称(上例中的oauth2)
  • 授权方案的描述
  • 流量 – 要使用的授权类型
  • 授权url – 应该是STSurl(例如: https : //auth2.test.com/oauth2/authorize )
  • 范围 – 范围名称

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

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

该方法接受以下参数:

  • clientId – 这应该是安全令牌服务中配置的swagger的客户端ID
  • clientSecret – 这应该是客户端密钥。 仅在代码授予类型的情况下才需要这样做
  • 领域 – 这应该是重定向url(这应该是[基地址] + 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().Any(); if (allowsAnonymous) { return; // must be an anonymous method } } if (operation != null) { if (operation.security == null) { operation.security = new List>>(); } var authRequirements = new Dictionary> { { "oauth2", new List { clientId } } }; operation.security.Add(authRequirements); } } } 

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

IV。 在swagger配置文件中添加上面的filter(参见下面的代码)

 c.OperationFilter(); 

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

VI。 在Web API项目中,如果有一个index.html用于注入特定于API的UI字段/样式,那么请确保使用swashbuckle版本的index.html文件保留所有javascript代码(如提供的那样)位置 – 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. 

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

我在这里描述了这个错误Swagger UI没有解析响应 ,这是由于IdentityServer3正确没有添加响应头“Access-Control-Allow-Origin: http:// localhost:62561 ”你可以通过更新你强制IdentityServer3发送该头客户端创建如下:

 new Client { ClientName = "SwaggerUI", Enabled = true, ClientId = "swaggerUI", ClientSecrets = new List { new Secret("PasswordGoesHere".Sha256()) }, Flow = Flows.ClientCredentials, AllowClientCredentialsOnly = true, AllowedScopes = new List { "Read" }, Claims = new List { 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 { "http://localhost:62561/" ,"http://portaldev.RogueOne.com" ,"https://portaldev.RogueOne.com" } } 

AllowedCorsOrigins是我拼图的最后一块。 希望这可以帮助面临同样问题的其他人