Need help to set up Hangfire Dashboard in .NET with ABP.io

Hello, everybody. I am new to this community but I wanted to join to get help from you in building the hangfire dashboard in my .NET Web API. I am so sorry to interrupt your precious time.

Now I am facing an issue in implementing authentication for hangfire dashboard.

There are authentication methods in my Web API.

  • One is JWT Authentication what is using in the backend authentication/authorization.
  • Another one is Basic Authentication what is using in the hangfire dashboard.

I logged in to the hangfire dashboard by username and password (these are coming from appsettings.json). And then, I tried to access to swagger in the same browser and got the error as you can see in the attached screenshot.

So I tried to debug the code and when passing the middleware (TokenParseMiddleware.cs) to verify the token if it’s JWT or not (if it’s not JWT, then this kind of error is caused.), token of Request header was the same one what I got when logging into the hangfire dashboard. In other word, it was just the basic auth token.

I am not sure what kind of things this issue will affected to the backend logic but I want to know how I can resolve this issue.

I’d like to get help from you, experts and resolve this issue ASAP.
Thank you for your time.

Here is the custom authentication filter what I wrote for hangfire dashboard authentication.

public class HangfireDashboardAuthFilter : IDashboardAuthorizationFilter
{
    public bool Authorize([NotNull] DashboardContext context)
    {
        var httpContext = context.GetHttpContext();

        var header = httpContext.Request.Headers["Authorization"];

        if (string.IsNullOrWhiteSpace(header))
        {
            SetChallengeResponse(httpContext);
            return false;
        }

        var authValues = System.Net.Http.Headers.AuthenticationHeaderValue.Parse(header);

        if (!"Basic".Equals(authValues.Scheme, StringComparison.InvariantCultureIgnoreCase))
        {
            SetChallengeResponse(httpContext);
            return false;
        }

        var parameter = System.Text.Encoding.UTF8.GetString(Convert.FromBase64String(authValues.Parameter));
        var parts = parameter.Split(':');

        if (parts.Length < 2)
        {
            SetChallengeResponse(httpContext);
            return false;
        }

        var username = parts[0];
        var password = parts[1];

        if (string.IsNullOrWhiteSpace(username) || string.IsNullOrWhiteSpace(password))
        {
            SetChallengeResponse(httpContext);
            return false;
        }

        if (username == "shiny" && password == "123")
        {
            return true;
        }

        SetChallengeResponse(httpContext);
        return false;
    }

    private void SetChallengeResponse(HttpContext httpContext)
    {
        httpContext.Response.StatusCode = 401;
        httpContext.Response.Headers.Append("WWW-Authenticate", "Basic realm=\"Hangfire Dashboard\"");
        httpContext.Response.WriteAsync("Authentication is required.");
    }
}

This code is what I have in Program.cs file.

public override void OnApplicationInitialization(ApplicationInitializationContext context)
{
    var app = context.GetApplicationBuilder();
    var env = context.GetEnvironment();
    var configuration = context.GetConfiguration();
    bool isProduction = Convert.ToBoolean(Helper.GetConfigSection("IsProduction"));

    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }

    app.UseAbpRequestLocalization();

    if (!env.IsDevelopment())
    {
        app.UseErrorPage();
    }

    app.UseCorrelationId();
    app.UseStaticFiles();
    app.UseRouting();
    app.UseCors();

    app.UseMiddleware<SasAppLoggingMiddleware>();
    app.UseMiddleware<TokenParseMiddleware>();

    app.UseAuthentication();

    app.UseAbpOpenIddictValidation();

    if (MultiTenancyConsts.IsEnabled)
    {
        app.UseMultiTenancy();
    }
    app.UseUnitOfWork();
    app.UseDynamicClaims();
    app.UseAuthorization();

    if (!isProduction)
    {
        app.UseSwagger();
        app.UseAbpSwaggerUI(c =>
        {
            c.SwaggerEndpoint("/swagger/v1/swagger.json", "SmartAuditSystem API");
        });
    }

    app.UseAbpHangfireDashboard("/backgrounds", options =>
    {
        options.DashboardTitle = "Smart Audit System";
        options.DisplayStorageConnectionString = false;
        options.Authorization = new[] { new HangfireDashboardAuthFilter() };
    });

    app.UseAuditing();
    app.UseAbpSerilogEnrichers();
    app.UseConfiguredEndpoints();
    app.UseJwtTokenMiddleware();
}