【发布时间】:2021-05-11 23:39:36
【问题描述】:
我有一个 ASP.NET Core 项目,它从 Sendgrid Webhook 接收数据并向业务用户 (Azure AD) 提供经过身份验证的 API。
Sendgrid is capable to be configured with OAuth 2.0 with client-credentials-flow 作为 webhook 接收器的身份验证。它不支持基本身份验证。 OAuth 或无。
我已经成功地为我的应用配置了 Sendgrid 的 OAuth 身份验证,利用 OpenIddict,暂时让其他 API 不受保护。现在我需要在投入生产之前使用 OAuth 隐式流保护这些其他 API。并且 Sendgrid 必须向 webhook 验证自己。我宁愿不部署额外的微服务。
简短的问题
在 ASP.NET Core 中是否有可能以及如何验证来自不同颁发者的 JWT?例如,您可以使用 Facebook、Twitter 或 Google 等登录的应用程序(见注 1)
现在,为了让外部观众完美清楚,我将添加一个详细无聊的解释。
到目前为止我的工作
这是我为配置 OpenIddict 所做的。
public static IServiceCollection ConfigureOpenIddictAuthentication(this IServiceCollection services)
{
services.AddDbContext<OpenIddictDbContext>(ef => ef
// Configure the context to use an in-memory store.
// This prevents multiple cluster instances from deployment
.UseInMemoryDatabase(nameof(OpenIddictDbContext))
// Register the entity sets needed by OpenIddict.
.UseOpenIddict()
)
.AddOpenIddict(options =>
options.AddServer(server => server
.DisableAccessTokenEncryption() //Just for development
//Development: no time to waste on certificate management today
.AddEphemeralEncryptionKey()
.AddEphemeralSigningKey()
.RegisterClaims(OpenIddictConstants.Claims.Role)
.RegisterScopes(OpenIddictConstants.Scopes.Roles)
.SetTokenEndpointUris("/api/v1/Auth/token")
.SetAuthorizationEndpointUris("/api/v1/Auth/authorize")
.AllowClientCredentialsFlow() //Only one supported by Sendgrid
.UseAspNetCore()
.EnableTokenEndpointPassthrough())
.AddCore(core => core.UseEntityFrameworkCore(ef => ef.UseDbContext<OpenIddictDbContext>()))
.AddValidation(validation => validation
.UseLocalServer(_ => { })
.UseAspNetCore(_ => { })
)
)
.AddHostedService<OpenIddictHostedService>()
.AddAuthentication(OpenIddictValidationAspNetCoreDefaults.AuthenticationScheme)
;
return services;
}
上述代码(以及未显示的OpenIddictHostedService)提供了客户端凭据流/api/v1/Auth/token URL、验证Sendgrid 提供的Bearer 令牌和隐藏在环境中的秘密凭据所需的所有基础设施。
我可以使用开发环境中托管的客户端凭据运行 Postman 测试以提交 Sendgrid 测试数据。它有效
添加 MSAL 后端
然后我在我的代码中关闭了 OpenIddict 一段时间以执行新的编码。我已经使用 OpenID Connect 和 OAuth 的隐式流程(Angular 和 Swagger 要求)配置了 MS AAD 应用程序注册。通过添加以下代码和适当的[Authorize] 属性,我可以使用代码保护我的其余 API:
services
.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApi(Configuration)
;
配置appSettings.json 包含租户、应用 ID 和 OIDC 元数据 URL。还有一个与 Swagger 相关的部分,它使用 MS Azure 元数据为 OIDC 配置 Swagger
services.AddSwaggerGen(swagger =>
{
swagger.SwaggerDoc("v1", new OpenApiInfo { Title = "...", Version = "v1" });
swagger.OperationFilter<AssignOAuth2SecurityRequirements>();
swagger.AddSecurityDefinition("AzureAD", new OpenApiSecurityScheme
{
Type = SecuritySchemeType.OpenIdConnect,
OpenIdConnectUrl = new Uri("https://login.microsoftonline.com/......./v2.0/.well-known/openid-configuration"),
});
swagger.AddSecurityRequirement(AssignOAuth2SecurityRequirements.APISECURITY);
});
public static readonly OpenApiSecurityRequirement APISECURITY = new OpenApiSecurityRequirement
{
{
new OpenApiSecurityScheme
{
Reference = new OpenApiReference
{
Type = ReferenceType.SecurityScheme,
Id = "oauth2"
}
},
new[] { "AzureAD" }
}
};
上述片段的结果是,Swagger 现在允许我使用 MS AAD 发布的 JWT 调用我项目的其他受保护 API
而且它该死的工作。但是现在 Sendgrid 的 OAuth 身份验证被关闭了。
合并两者
现在我需要每个受 [Authorize] 保护的 API 检查标头中提供的 any 的 JWT 令牌(注 3:我将在下一次编码迭代中使用范围来区分)验证请求,无论它来自 Sendgrid/Postman 还是 Swagger/Angular。
我试图取消注释我的所有代码
services.ConfigureOpenIddictAuthentication();
services
.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApi(Configuration);
但它在使用 OpenIddict 授权服务器进行身份验证时惨遭失败。 IE。它只检查 MSAL 令牌并拒绝整个请求。显然,后面注册的授权服务会覆盖前面的。
注 1
实际上,从设计的角度来看,为了使用多个提供者实现身份验证,应该实现一个端点,以交换来自外部提供者的令牌,以换取由本地权威机构颁发的令牌。但是 Microsoft AAD 使用 Microsoft Azure 本身发布的 JWT 作为承载。为什么不使用它们?
【问题讨论】:
标签: c# authentication azure-active-directory asp.net-core-webapi