在 Swashbuckle 中启用 Oauth2 客户端凭据流
Enable Oauth2 client credentials flow in Swashbuckle
我使用 IdentityServer3 通过客户端凭据授权来保护 Web API。对于使用 Swashbuckle 的文档,我无法弄清楚如何在 SwaggerConfig 中为客户端凭据(应用程序)流启用 Oauth2。如有任何帮助,我们将不胜感激!
我能够让它工作。大部分答案都可以找到here.
为了让 client_credential 拨款发挥作用,我必须更改一些部分。
第一部分在 EnableSwagger 和 EnableSwaggerUi 调用中:
config.EnableSwagger(c =>
{
c.SingleApiVersion("v1", "sample api");
c.OAuth2("oauth2")
.Description("client credentials grant flow")
.Flow("application")
.Scopes(scopes => scopes.Add("sampleapi", "try out the sample api"))
.TokenUrl("http://authuri/token");
c.OperationFilter<AssignOAuth2SecurityRequirements>();
}).EnableSwaggerUi(c =>
{
c.EnableOAuth2Support("sampleapi", "samplerealm", "Swagger UI");
});
这里的重要变化是 .Flow("application")
我还使用了 .TokenUrl
调用而不是 .AuthorizationUrl
这仅取决于您设置的特定授权方案。
我也用了稍微不同的AssignOAuth2SecurityRequirements
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);
}
}
这应该足以显示身份验证开关。对我来说,另一个问题是设置了默认身份验证对话框,因此用户只需 select 一个范围,然后单击授权。在我的例子中,由于我设置身份验证的方式,这不起作用。我不得不重新编写 swagger-oauth.js 脚本中的对话框并将其注入 SwaggerUI。
我在使这一切正常工作时遇到了一些麻烦,但在坚持不懈之后,我找到了一个无需向 SwaggerUI 中注入任何 JavaScript 即可工作的解决方案。注意:我的部分困难可能是由于使用 IdentityServer3,这是一个很棒的产品,只是不知道配置问题。
我的大部分更改与上面的账单答案类似,但我的操作过滤器不同。在我的控制器中,所有方法都有一个授权标签,没有像这样的角色:
[Authorize]
// Not this
[Authorize(Roles = "Read")] // This doesn't work for me.
在 Authorize 标签上没有定义角色的情况下,OperationFilter 看起来像这样:
public void Apply(Operation operation, SchemaRegistry schemaRegistry, ApiDescription apiDescription)
{
// Correspond each "Authorize" role to an oauth2 scope, since I don't have any "Roles" defined, this didn't work
// and is in most of the Apply methods I found online. If you are like me and your [Authorize] tag doesn't contain
// any roles this will not work.
//var scopes = apiDescription.ActionDescriptor.GetFilterPipeline()
// .Select(filterInfo => filterInfo.Instance)
// .OfType<AuthorizeAttribute>()
// .SelectMany(attr => attr.Roles.Split(','))
// .Distinct();
var scopes = new List<string>() { "Read" }; // For me I just had one scope that is added to all all my methods, you might have to be more selective on how scopes are added.
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);
}
}
SwaggerConfig 如下所示:
public static void Register()
{
var thisAssembly = typeof(SwaggerConfig).Assembly;
GlobalConfiguration.Configuration
.EnableSwagger(c =>
{
c.SingleApiVersion("v1", "waPortal");
c.OAuth2("oauth2")
.Description("OAuth2 Client Credentials Grant Flow")
.Flow("application")
.TokenUrl("http://security.RogueOne.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: "swaggerUI",
clientSecret: "BigSecretWooH00",
realm: "swagger-realm",
appName: "Swagger UI"
);
});
}
最后一部分是最难弄清楚的,我最终在 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.
我在此处描述了这个错误 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 是我的最后一块拼图。希望这可以帮助面临同样问题的其他人
我使用 IdentityServer3 通过客户端凭据授权来保护 Web API。对于使用 Swashbuckle 的文档,我无法弄清楚如何在 SwaggerConfig 中为客户端凭据(应用程序)流启用 Oauth2。如有任何帮助,我们将不胜感激!
我能够让它工作。大部分答案都可以找到here.
为了让 client_credential 拨款发挥作用,我必须更改一些部分。 第一部分在 EnableSwagger 和 EnableSwaggerUi 调用中:
config.EnableSwagger(c =>
{
c.SingleApiVersion("v1", "sample api");
c.OAuth2("oauth2")
.Description("client credentials grant flow")
.Flow("application")
.Scopes(scopes => scopes.Add("sampleapi", "try out the sample api"))
.TokenUrl("http://authuri/token");
c.OperationFilter<AssignOAuth2SecurityRequirements>();
}).EnableSwaggerUi(c =>
{
c.EnableOAuth2Support("sampleapi", "samplerealm", "Swagger UI");
});
这里的重要变化是 .Flow("application")
我还使用了 .TokenUrl
调用而不是 .AuthorizationUrl
这仅取决于您设置的特定授权方案。
我也用了稍微不同的AssignOAuth2SecurityRequirements
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);
}
}
这应该足以显示身份验证开关。对我来说,另一个问题是设置了默认身份验证对话框,因此用户只需 select 一个范围,然后单击授权。在我的例子中,由于我设置身份验证的方式,这不起作用。我不得不重新编写 swagger-oauth.js 脚本中的对话框并将其注入 SwaggerUI。
我在使这一切正常工作时遇到了一些麻烦,但在坚持不懈之后,我找到了一个无需向 SwaggerUI 中注入任何 JavaScript 即可工作的解决方案。注意:我的部分困难可能是由于使用 IdentityServer3,这是一个很棒的产品,只是不知道配置问题。
我的大部分更改与上面的账单答案类似,但我的操作过滤器不同。在我的控制器中,所有方法都有一个授权标签,没有像这样的角色:
[Authorize]
// Not this
[Authorize(Roles = "Read")] // This doesn't work for me.
在 Authorize 标签上没有定义角色的情况下,OperationFilter 看起来像这样:
public void Apply(Operation operation, SchemaRegistry schemaRegistry, ApiDescription apiDescription)
{
// Correspond each "Authorize" role to an oauth2 scope, since I don't have any "Roles" defined, this didn't work
// and is in most of the Apply methods I found online. If you are like me and your [Authorize] tag doesn't contain
// any roles this will not work.
//var scopes = apiDescription.ActionDescriptor.GetFilterPipeline()
// .Select(filterInfo => filterInfo.Instance)
// .OfType<AuthorizeAttribute>()
// .SelectMany(attr => attr.Roles.Split(','))
// .Distinct();
var scopes = new List<string>() { "Read" }; // For me I just had one scope that is added to all all my methods, you might have to be more selective on how scopes are added.
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);
}
}
SwaggerConfig 如下所示:
public static void Register()
{
var thisAssembly = typeof(SwaggerConfig).Assembly;
GlobalConfiguration.Configuration
.EnableSwagger(c =>
{
c.SingleApiVersion("v1", "waPortal");
c.OAuth2("oauth2")
.Description("OAuth2 Client Credentials Grant Flow")
.Flow("application")
.TokenUrl("http://security.RogueOne.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: "swaggerUI",
clientSecret: "BigSecretWooH00",
realm: "swagger-realm",
appName: "Swagger UI"
);
});
}
最后一部分是最难弄清楚的,我最终在 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.
我在此处描述了这个错误 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 是我的最后一块拼图。希望这可以帮助面临同样问题的其他人