Pat*_*ski 7 c# swagger swagger-ui openid-connect swashbuckle
如何设置 Swashbuckle 和 Swagger UI 以使用 Open ID Connect Discovery 进行授权(在我的例子中是 Azure AD)?
到目前为止,这是我的(未完全工作的)SwaggerGen 设置,基于/sf/answers/4630359751/:
SwaggerGenOptions c => {
OpenApiInfo apiInfo = new() { /* ...snip... */ };
c.SwaggerDoc("v1", apiInfo);
IncludeXmlFileForSwagger(c);
// Defines the Open ID Connect discovery scheme - see also /sf/answers/4630359751/
OpenApiSecurityScheme mainScheme = new()
{
Type = SecuritySchemeType.OpenIdConnect,
OpenIdConnectUrl = new Uri($"https://login.microsoftonline.com/{myTenantId}/.well-known/openid-configuration"),
};
c.AddSecurityDefinition("OpenIdConnect", mainScheme);
// Adds a reference to the above scheme as required for every API action (we can get more nuanced later)
// Note: if just try to use mainScheme instead, it doesn't apply a Bearer token)
OpenApiSecurityScheme securityScheme = new() {
Reference = new OpenApiReference {
Type = ReferenceType.SecurityScheme, Id = "OpenIdConnect"
}
};
OpenApiSecurityRequirement securityRequirements = new() { {securityScheme, Array.Empty<string>()} };
c.AddSecurityRequirement(securityRequirements);
}
Run Code Online (Sandbox Code Playgroud)
...在静态配置方法中,我...
SwaggerGenOptions c => {
OpenApiInfo apiInfo = new() { /* ...snip... */ };
c.SwaggerDoc("v1", apiInfo);
IncludeXmlFileForSwagger(c);
// Defines the Open ID Connect discovery scheme - see also https://stackoverflow.com/a/66147996/7453
OpenApiSecurityScheme mainScheme = new()
{
Type = SecuritySchemeType.OpenIdConnect,
OpenIdConnectUrl = new Uri($"https://login.microsoftonline.com/{myTenantId}/.well-known/openid-configuration"),
};
c.AddSecurityDefinition("OpenIdConnect", mainScheme);
// Adds a reference to the above scheme as required for every API action (we can get more nuanced later)
// Note: if just try to use mainScheme instead, it doesn't apply a Bearer token)
OpenApiSecurityScheme securityScheme = new() {
Reference = new OpenApiReference {
Type = ReferenceType.SecurityScheme, Id = "OpenIdConnect"
}
};
OpenApiSecurityRequirement securityRequirements = new() { {securityScheme, Array.Empty<string>()} };
c.AddSecurityRequirement(securityRequirements);
}
Run Code Online (Sandbox Code Playgroud)
因此,上面的代码让我可以验证并检查名为“openid”的范围,并显示“锁定的”挂锁。当我尝试通过 Swagger UI 运行操作时,它提供了一个不记名令牌,但它返回无效。
我是否需要以某种方式指定一个显式命名范围,而不是“openid”?如何?
我的设置正确吗?如果是这样,为什么令牌无效?有什么解决问题的想法吗?
由于 Swagger UI 使用 Web 浏览器上下文来发出请求,因此我发现只需在顶部提供一个链接,将它们带到任何需要身份验证的 API 调用,然后还对所有内容添加安全要求,就可以更轻松、更简单地进行请求。需要授权的功能。
如果您的 API 自动重定向并使用浏览器功能进行登录(我认为大多数人都会这样做),那么这将起作用。用户登录后,来自 Swagger UI 的所有未来 HTTP 请求都将发送 auth cookie,就像直接访问浏览器中的端点一样。
首先,Startup.cs 中的 Swagger 配置,包括一个方便用户登录的链接:
services.AddSwaggerGen(c => {
OpenApiInfo apiInfo = new()
{
Title = "MyService",
Version = "v1",
Description = "<p>An API for working with ... "
+ "<p>If you get '<b>Failed to fetch</b>' below on an action that shows a padlock icon, this likely "
+ "means you are not <b>signed in</b>, so "
+ "<a target=\"_blank\" href=\"/api/v1/security/signIn\">sign in here</a>, then "
+ "your sign-in will take effect for any action below.",
};
c.SwaggerDoc("v1", apiInfo);
/* put other configuration here, such as c.IncludeXmlComments */
c.OperationFilter<MethodNeedsAuthorizationFilter>(); // puts auth UI on the right actions
});
Run Code Online (Sandbox Code Playgroud)
在上面的例子中,我的端点/api/v1/security/signIn需要授权;您可以使用需要授权的任何端点。
然后,这是您需要启用适当显示打开的挂锁图标的 MethodNeedsAuthorizationFilter:
using Microsoft.AspNetCore.Authorization;
using Microsoft.OpenApi.Models;
using Swashbuckle.AspNetCore.SwaggerGen;
using System;
using System.Collections.Generic;
using System.Linq;
namespace GeneralMills.TradePlannerService;
/// <summary>
/// Provides a method that applies Swagger UI security requirements to all controller actions that need authorization.
/// </summary>
public class MethodNeedsAuthorizationFilter : IOperationFilter
{
public void Apply(OpenApiOperation operation, OperationFilterContext context)
{
if (operation is null) throw new ArgumentNullException(nameof(operation));
if (context is null) throw new ArgumentNullException(nameof(context));
object[] methodAttributes = context.MethodInfo.GetCustomAttributes(true);
bool needsAuth =
methodAttributes.OfType<AuthorizeAttribute>().Any()
|| (context.MethodInfo.DeclaringType != null
&& context.MethodInfo.DeclaringType.GetCustomAttributes(true).OfType<AuthorizeAttribute>().Any()
&& !methodAttributes.OfType<AllowAnonymousAttribute>().Any());
if (needsAuth)
{
OpenApiSecurityScheme scheme = new()
{
Reference = new OpenApiReference { Type = ReferenceType.SecurityScheme, Id = "ExampleName" },
Scheme = "ExampleName",
Name = "ExampleName",
In = ParameterLocation.Header,
};
operation.Security = new List<OpenApiSecurityRequirement>()
{
new () { {scheme, new List<string>() } }
};
}
}
}
Run Code Online (Sandbox Code Playgroud)
这有效地规避了 Swagger UI 的内置授权支持,而我无法使用它。