【问题标题】:Can two authentication systems co-exist in ASP.NET Core Web API?ASP.NET Core Web API 中可以同时存在两个身份验证系统吗?
【发布时间】: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


    【解决方案1】:

    我可能找到了一个不错的解决方法。感谢Use multiple JWT Bearer Authenticationhttps://stackoverflow.com/a/49706390/471213的回答

    我所做的是将 MSAL 提升为 JWT Bearer Default 身份验证,以便默认情况下每个 API 都使用 AAD 令牌进行身份验证。

    相反,在 Sendgrid Webhook API 上,我使用 [Authorize(AuthenticationSchemes = OpenIddictValidationAspNetCoreDefaults.AuthenticationScheme)] 明确告诉 ASP .NET Core 我只想对 that API 使用 that OpenIddict 方案。

    结果:

            services.ConfigureOpenIddictAuthentication();
    
            services
                .AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
                .AddMicrosoftIdentityWebApi(Configuration)
    

    ConfigureOpenIddictAuthentication() 本身也会发生变化

            .AddHostedService<OpenIddictHostedService>()
            .AddAuthentication() // Probably not necessary, at least DO NOT add default scheme here
            ;
    

    【讨论】:

    • 这是一种变通方法,只有当 Sendgrid 使用专用 API 而不是 Angular 和世界其他地方的 API 时我很高兴
    猜你喜欢
    • 2016-12-22
    • 2022-01-27
    • 2018-01-28
    • 2017-11-24
    • 2018-03-05
    • 2021-03-02
    • 2020-07-27
    • 2018-03-15
    • 2012-06-16
    相关资源
    最近更新 更多