Search code examples
asp.net-mvcforms-authenticationhangfire

Why is Hangfire requiring authentication to view dashboard


I am running HangFire within my MVC web app but whenever I try to navigate to http://MyApp/hangfire, it redirects me to my app's login page as though I am not logged in.

I have not explicitly configured any requirements for authorization...e.g. I had the below in the web.config, but then took it out in attempts to get this to work.

<location path="hangfire">
<system.web>
  <authorization>
    <allow roles="Administrator" />
    <deny users="*" />  
  </authorization>
</system.web>

In theory, this is what I'd want, and when I log into my main web application, I will be logged in with an Administrator role so this rule should work.

But whether I have that configured in the web.config or not, whenever I try to navigate to http://MyApp/hangfire, it redirects me to my apps login page as configured in the web.config:

<authentication mode="Forms">
  <forms loginUrl="~/Account/Login" timeout="960" />
</authentication>

It does NOT do this on my local machine, just when I publish to my host. Does HangFire not recognize the authentication cookie that my main app provides when I login? I thought in general, the hangfire app doesn't require authentication, so what other configuration could be thinking that it does?

UPDATE 1:

I added the authorization filters per the hangfire docs, but the same thing happens. Here is my code in Startup.cs:

using Hangfire;
using Hangfire.Logging;
using Hangfire.Dashboard;
using Hangfire.SqlServer;
using Microsoft.Owin;
using OTIS.Web.AppCode;
using OTISScheduler.AppServ;
using Owin;
using System.Web.Security;

[assembly: OwinStartup(typeof(OTIS.Web.App_Start.Startup))]
namespace OTIS.Web.App_Start
{
    public class Startup
    {
        public void Configuration(IAppBuilder app) {

            app.UseHangfire(config => {
                config.UseSqlServerStorage("DefaultConnection");
                config.UseServer();

                //Dashboard authorization
                config.UseAuthorizationFilters(new AuthorizationFilter
                {
                    Users = "USERA", // allow only specified users (comma delimited list)
                    Roles = "Account Administrator, Administrator" // allow only specified roles(comma delimited list)
                });


            });

            LogProvider.SetCurrentLogProvider(new StubLogProviderForHangfire());

            GlobalJobFilters.Filters.Add(new AutomaticRetryAttribute { Attempts = 0 });

            var scheduleTasksInitializer = new ScheduleTasksInitializer();

            scheduleTasksInitializer.ScheduleTasks();
        }
    }
}

UPDATE 2:

Per the more detailed instructions showing basic authentication, I also tried this...still no luck..redirects me to my app's login page.

config.UseAuthorizationFilters(
new BasicAuthAuthorizationFilter(
    new BasicAuthAuthorizationFilterOptions
    {
        // Require secure connection for dashboard
        RequireSsl = false,
        SslRedirect = false,

        // Case sensitive login checking
        LoginCaseSensitive = true,

        // Users
        Users = new[]
        {
            new BasicAuthAuthorizationUser
            {
                Login = "MyLogin",

                // Password as plain text
                PasswordClear = "MyPwd"
            }
        }
    }));          

Solution

  • Finally got it working. I created my own AuthorizationFilter class (see below). Then I passed that to the MapHangfireDashboard method in the Startup.cs Configuration method (see below that)

    public class HangFireAuthorizationFilter : IAuthorizationFilter
    {
        public bool Authorize(IDictionary<string, object> owinEnvironment)
        {
            bool boolAuthorizeCurrentUserToAccessHangFireDashboard = false;
    
            if (HttpContext.Current.User.Identity.IsAuthenticated)
            {
                if(HttpContext.Current.User.IsInRole("Account Administrator"))
                    boolAuthorizeCurrentUserToAccessHangFireDashboard = true;
            }
    
            return boolAuthorizeCurrentUserToAccessHangFireDashboard;
        }
    }
    

    To map hangfire to a custom url and specify the AuthorizationFilter to use:

    public void Configuration(IAppBuilder app) {
    
        //Get from web.config to determine to fire up hangfire scheduler or not
    
        app.UseHangfire(config => {
            config.UseSqlServerStorage("DefaultConnection");
            config.UseServer();              
        });
    
        //map hangfire to a url and specify the authorization filter to use to allow access
        app.MapHangfireDashboard("/Admin/jobs", new[] { new HangFireAuthorizationFilter() });
    
    }