具有 Azure AD 登录功能的 .NET Core WebApi 安全 Hangfire 仪表板

bbr*_*nck 6 .net asp.net-web-api azure-active-directory hangfire asp.net-core

我目前正在尝试保护对 Hangfire 仪表板的访问。

由于我使用 .NET Core WebApi,我真的不知道如何使用 Azure AD 保护仪表板。

我尝试使用策略,但没有成功:

services.AddAuthorization(options =>
            {
                // Policy to be applied to hangfire endpoint
                options.AddPolicy(AppConstants.HangfirePoilicyName, builder =>
                {
                    builder
                        .AddAuthenticationSchemes(AzureADDefaults.AuthenticationScheme)
                        .RequireAuthenticatedUser();
                });
            });
Run Code Online (Sandbox Code Playgroud)

这里是配置方法:

app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllerRoute(
                        name: "default",
                        pattern: "{controller}/{action=Index}/{id?}")
                    .RequireAuthorization();
                
                endpoints.MapHangfireDashboard("/hangfire", new DashboardOptions()
                    {
                        Authorization = new List<IDashboardAuthorizationFilter> { }
                    })
                    .RequireAuthorization(AppConstants.HangfirePoilicyName);
            });
Run Code Online (Sandbox Code Playgroud)

我期望的是,当我转到 Hangfire 仪表板时,我会看到 Microsoft 通过 Azure AD 登录,然后登录到我的租户并获得仪表板的访问权限。

也许值得一提:默认身份验证是 JWTBearerDefaults,但对于 Hangfire 仪表板,我需要 AzureAdDefaults

jar*_*smk 6

一些序言信息:

  • 我的解决方案是使用 .NET Core 6 遵循 MSAL 2 流程的实现。
  • 对于声明:

默认身份验证是 JWTBearerDefaults,但对于 Hangfire 仪表板,我需要 AzureAdDefaults

AzureAdDefaults 现在已过时,因此您需要使用其他东西,例如 JWTBearerDefaults,但请继续阅读以了解我的实现如何工作。

  • 对我来说另一个令人困惑的事情是 WebApi 也充当 WebApp,因为您在某些端点上启用了类似应用程序的身份验证,但在其他端点上则不然。事实证明这是可能的。

解决方案:

经过大量浏览代码示例后,我发现了这个金块:

services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
          .AddMicrosoftIdentityWebApp(Configuration.GetSection("AzureAd"))
              .EnableTokenAcquisitionToCallDownstreamApi(initialScopes)
                  .AddMicrosoftGraph(Configuration.GetSection("DownstreamApi"))
                  .AddInMemoryTokenCaches();

services.AddAuthentication()
        .AddMicrosoftIdentityWebApi(Configuration.GetSection("AzureAd"),
                                    JwtBearerDefaults.AuthenticationScheme)
        .EnableTokenAcquisitionToCallDownstreamApi();
Run Code Online (Sandbox Code Playgroud)

本质上,这意味着您可以对 进行 2 个单独的调用.AddAuthentication(...),其中 1 个调用链接AddMicrosoftIdentityWebApp,另一个AddMicrosoftIdentityWebApi调用,指定在两种情况下使用哪种身份验证。

对我来说,我将 Api 设置为使用 进行身份验证JwtBearerDefaults.AuthenticationScheme,WebApp 部分使用OpenIdConnectDefaults.AuthenticationScheme,使其看起来像这样:

services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
            .AddMicrosoftIdentityWebApi(Configuration.GetSection("AzureAd"),
                                  JwtBearerDefaults.AuthenticationScheme);

services.AddAuthentication()
            .AddMicrosoftIdentityWebApp(Configuration, "AzureAd", OpenIdConnectDefaults.AuthenticationScheme);
Run Code Online (Sandbox Code Playgroud)

接下来,设置 Hangfire 使用的策略,该策略与之前为 WebApp 部分设置的方案相匹配。

services.AddAuthorization(options =>
        {
            options.AddPolicy("azureAdPolicy", builder =>
            {
                builder
                    .AddAuthenticationSchemes(OpenIdConnectDefaults.AuthenticationScheme)
                    .RequireAuthenticatedUser();
            });
        });
Run Code Online (Sandbox Code Playgroud)

然后,我创建了一些扩展方法来设置 Hangfire 服务和路由。

public static IServiceCollection AddHangfireService(
        this IServiceCollection services, 
        IConfiguration configuration)
    {
        services.AddHangfireServer();
        services.AddHangfire(cfg =>
        {
            // Additional setup code
        });
        return services;
    }
Run Code Online (Sandbox Code Playgroud)

像这样调用:

 services.AddHangfireService(Configuration);
Run Code Online (Sandbox Code Playgroud)

对于路由:

public static IEndpointRouteBuilder AddHangfireRoute(this IEndpointRouteBuilder endpoints,
        HangfireDBOptions hangfireDbOptions)
    {
        endpoints.MapHangfireDashboard("/hangfire", new DashboardOptions
        {
            DashboardTitle = "Your App Title",
            AppPath = hangfireDbOptions.BackToSiteUrl,
            Authorization = new[]
            {
                new HangfireDashboardAuthFilter() // if you need a filter
            }
        })
        .RequireAuthorization("azureAdPolicy"); // Matches your policy name
        return endpoints;
    }
Run Code Online (Sandbox Code Playgroud)

其名称如下:

app.UseEndpoints(endpoints =>
        {
            endpoints.MapControllers(); // Call this first

            endpoints.AddHangfireRoute(hangfireOptions);
        });
Run Code Online (Sandbox Code Playgroud)

剩下要做的唯一一件事就是在 Azure AD 环境中正确配置 Hangfire 路由。

在您的应用程序注册中,添加 Web 应用程序类型,并添加以下路由:

  • (您的基本应用程序 URL)/signin-oidc
  • (您的基本应用程序 URL)
  • (您的基本应用程序 URL)/hangfire

并确保选中 ID 令牌复选框

Azure AD ID 令牌复选框的屏幕截图

应该是这样:)希望这会有所帮助,您的应用程序可能正在使用其他身份验证流程或较旧的库版本等 - 这就是我目前正在生产中使用的工作。无论如何,我建议您升级您的软件包,因为有很多“更好”的身份验证流程可供使用,并且正如我所提到的,某些功能现在已经过时。

对于延迟答复再次深表歉意,需要编译的信息相当多


Kus*_*eck 1

我认为您缺少对 AzureAdDefaults 的 AddAuthentication 调用:

services.AddAuthentication(AzureADDefaults.AuthenticationScheme)
        .AddAzureAD(options => Configuration.Bind("AzureAd", options));
Run Code Online (Sandbox Code Playgroud)

通过此调用,其余代码应该可以工作。正如您所提到的,您的策略必须针对 AzureAdDefaults,因此您需要为该方案添加身份验证。

其中AzureAd是以下配置:

"AzureAd": {
    "Instance": "https://login.microsoftonline.com/",
    "Domain": "[Enter the domain of your tenant, e.g. contoso.onmicrosoft.com]",
    "TenantId": "[Enter 'common', or 'organizations' or the Tenant Id (Obtained from the Azure portal. Select 'Endpoints' from the 'App registrations' blade and use the GUID in any of the URLs), e.g. da41245a5-11b3-996c-00a8-4d99re19f292]",
    "ClientId": "[Enter the Client Id (Application ID obtained from the Azure portal), e.g. ba74781c2-53c2-442a-97c2-3d60re42f403]"
}
Run Code Online (Sandbox Code Playgroud)