1

我的应用程序是在 ASP.Net Core 5 上运行的 Angular 12 应用程序。

我目前正在尝试锁定 Hangfire,以便它仅适用于具有管理员角色的人。

它使用 Microsoft 身份登录 - 特别是在 Azure 中设置的单点登录。

public void ConfigureServices(IServiceCollection services)
{
...
   services.AddHangfire(x =>
   {
      x.UseSqlServerStorage(sqlServerConnectionString);
   });
...
   services
      .AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
      .AddMicrosoftIdentityWebApi(Configuration);
...
}


public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
...
   app.UseAuthentication();
   app.UseRouting();
   app.UseAuthorization();

   app.UseHangfireDashboard("/hangfire", new DashboardOptions
   {
       Authorization = new[] {
          new HangfireAuthorisationFilter()
          },
          AppPath = "/"
   });

...
   app.UseEndpoints(endpoints => {
   ...
   });

   app.UseSpa(spa=>{
      ...
   });

}

这适用于我的点网核心控制器。

我需要做的就是添加 Authorize 属性:

namespace MyAppName.Controllers
{
    [Produces("application/json")]
    [Route("api/MyRoute")]
    [Authorize(Roles="Role1,Role2,Administrator")]
    public class MyControllerController: MyBaseApiController
    {
...
    }
}

但是当我想在 Hangfire 中进行授权时,用户对象缺少很多属性。

这是 HangfireAuthorisationFilter:

public class HangfireAuthorisationFilter : IDashboardAuthorizationFilter
{

   public HangfireAuthorisationFilter()
   {
   }

   public bool Authorize(DashboardContext context)
   {
      var httpContext = context.GetHttpContext();
      // the next line always fails. The User object is set. The Identity object is set
      // but there are no claims and the User.Name is null. There are also no roles set.
      return httpContext.User.Identity.IsAuthenticated;
   }
}

但是,有 cookie 信息,其中包含 msal cookie: httpContext.Request.Cookies

如何将身份验证信息传递给 Hangfire Authorize 方法?如何访问角色信息,以便将其锁定为仅管理员角色?有没有办法可以在服务器端解码 msal cookie?

4

2 回答 2

1

假设您有一个如下所示的 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]"
}

我认为避免手动验证令牌的更好方法是将代码更改为以下内容:

public void ConfigureServices(IServiceCollection services)
{

   services.AddHangfire(x =>
   {
      x.UseSqlServerStorage(sqlServerConnectionString);
   });

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

   services.
       .AddAuthentication(AzureADDefaults.AuthenticationScheme)
       .AddAzureAD(options => Configuration.Bind("AzureAd", options));

   services.AddAuthorization(options =>
        {
            options.AddPolicy("Hangfire", builder =>
            {
                builder
                    .AddAuthenticationSchemes(AzureADDefaults.AuthenticationScheme)
                    .RequireRole("Admin")
                    .RequireAuthenticatedUser();
            });
        });
}


public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
   app.UseAuthentication();
   app.UseRouting();
   app.UseAuthorization();

   app.UseEndpoints(endpoints =>
        {
            endpoints.MapControllers();
            endpoints.MapHangfireDashboard("/hangfire", new DashboardOptions()
            {
                Authorization = Enumerable.Empty<IDashboardAuthorizationFilter>()
            })
            .RequireAuthorization("Hangfire");
        });
 }

为了打破这一点,进行了以下更改:

  • 添加身份验证,AzureADDefaults.AuthenticationScheme以便我们可以创建需要“管理员”角色的策略。
  • 添加一个名为“Hangfire”的策略,该策略需要针对用户的“管理员”角色。看AddAuthorization电话。
  • 我们不是UseHangfireDashboard调用MapHangfireDashboard内部调用,而是UseEndpoints使用我们的“Hangfire”策略通过调用来保护hangfire仪表板端点RequireAuthorization("Hangfire")
  • 删除不需要的 HangfireAuthorisationFilter,而是在MapHangfireDashboard调用中传递一个空的过滤器集合。

关键的一点是,我们现在依赖的是中间件提供的安全性,而不是中间件的实现IDashboardAuthorizationFilter带来了令牌无效和/或逻辑错误的巨大风险。

于 2021-11-23T15:52:11.980 回答
0

好的,我已经知道如何解码 msal cookie 以获取我的声明和角色列表,并使用 Hangfire 成功授权

using Hangfire.Dashboard;
using System.IdentityModel.Tokens.Jwt;


namespace MyApp.Filters
{
    public class HangfireAuthorisationFilter : IDashboardAuthorizationFilter
    {

        public HangfireAuthorisationFilter()
        {
        }

        public bool Authorize(DashboardContext context)
        {

            var httpContext = context.GetHttpContext();
            var cookies = httpContext.Request.Cookies;
            var msalIdToken = cookies["msal.{your app client id goes here}.idtoken"];
            var token = new JwtSecurityTokenHandler().ReadJwtToken(msalIdToken);
            foreach(var claim in token.Claims)
            {
                if (claim.Type=="roles" && claim.Value == "Admin")
                {
                    return true;
                }
            }
            return false;
        }

    }
}
于 2021-09-08T01:43:24.437 回答