【问题标题】:Can't access hangfire dashboard无法访问hangfire仪表板
【发布时间】:2019-07-23 14:03:22
【问题描述】:

当我尝试访问 localhost:5000/hangfire 时,我被重定向到错误页面(我有一个返回相关状态页面的控制器(400,404 等))

这是我得到的错误:

我想 /hangfire 不存在。它所指的“HandeErrorCode”来自我的控制器。

[Route ("Error/{statusCode}")]
        public IActionResult HandleErrorCode (int statusCode) {
            var statusCodeData = 
HttpContext.Features.Get<IStatusCodeReExecuteFeature> ();

        switch (statusCode) {
            case 404:
                return View("Status404");
            case 401:
                return View("Status401");
            case 400:
                return View("Status400");    
            case 500:
                return View("Status500");
        }

        return View ();
    }

启动.cs

配置服务

services.AddHangfire(configuration=>{
              configuration.UsePostgreSqlStorage(connectionString);
          }); 

配置

app.UseHangfireDashboard("/hangfire");    
      app.UseHangfireServer();

编辑: 整个 Startup.cs

public class Startup {
public Startup (IHostingEnvironment env) {

  Console.WriteLine ("startin app {0}, which uses env {1} and has root {2}", env.ApplicationName, env.EnvironmentName, env.ContentRootPath);
  Configuration = new ConfigurationBuilder ()
    .SetBasePath (env.ContentRootPath)
    .AddJsonFile ("appsettings.json", optional : true, reloadOnChange : true)
    .AddJsonFile ($"appsettings.{env.EnvironmentName}.json", optional : true)
    .AddEnvironmentVariables ()
    .Build ();

  Console.WriteLine ("Current env variables are as follows: ");
  var enumerator = Environment.GetEnvironmentVariables ().GetEnumerator ();
  while (enumerator.MoveNext ()) {
    Console.WriteLine ($"{enumerator.Key,5}:{enumerator.Value,100}");
  }

}

public IConfigurationRoot Configuration { get; }

// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices (IServiceCollection services) {

  services.AddMvc ();
  // Add framework services.
  var connectionString = Configuration["ConnectionStrings:DefaultConnection"];

  Console.WriteLine ("using conn str: {0}", connectionString);
  services.AddEntityFrameworkNpgsql ()
    .AddDbContext<EntityContext> (
      options => options.UseNpgsql (connectionString)

    );
  services.AddIdentity<User, Role> (config => {
      config.SignIn.RequireConfirmedEmail = true;
    })
    .AddEntityFrameworkStores<EntityContext> ()
    .AddDefaultTokenProviders ();

  services.Configure<IdentityOptions> (options => {
    options.Password.RequireDigit = false;
    options.Password.RequiredLength = 5;
    options.Password.RequireLowercase = false;
    options.Password.RequireNonAlphanumeric = false;
    options.Password.RequireUppercase = false;
  });

  services.ConfigureApplicationCookie (options => options.LoginPath = "/account/login");

  services.AddAuthentication (CookieAuthenticationDefaults.AuthenticationScheme)
    .AddCookie (options => {
      options.LoginPath = "/Account/Login";
      options.LogoutPath = "/Account/Logout";
    });

  // SERVICE FILTERS
  services.AddScoped<ActivePackageFilterAttribute, ActivePackageFilterAttribute> ();
  services.AddScoped<ActiveUserFilterAttribute, ActiveUserFilterAttribute> ();
  services.AddSingleton<AccountBilling, AccountBilling> ();

  services.AddMemoryCache ();

  services.AddHangfire (configuration => {
    configuration.UsePostgreSqlStorage (connectionString);
  });

  services.AddMvc (config => {
      config.ModelBinderProviders.Insert (0, new InvariantDecimalModelBinderProvider ());
      //config.Filters.Add(typeof(RedirectActionFilter));
    })
    .SetCompatibilityVersion (CompatibilityVersion.Version_2_2)
    .AddJsonOptions (options => {
      options.SerializerSettings.ContractResolver = new DefaultContractResolver ();
      options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
    })
    .AddViewLocalization (LanguageViewLocationExpanderFormat.Suffix, opts => { opts.ResourcesPath = "Resources"; })
    .AddDataAnnotationsLocalization ();

  //services.AddScoped<RedirectActionFilter>();
  services.AddAutoMapper ();

  services.AddSingleton<AutoMapper.IConfigurationProvider> (Automapper.AutoMapperConfig.RegisterMappings ());

  //services.AddSingleton(Mapper.Configuration);
  services.AddScoped<IMapper> (sp => new Mapper (sp.GetRequiredService<AutoMapper.IConfigurationProvider> (), sp.GetService));

  services.AddDistributedMemoryCache (); // Adds a default in-memory implementation of IDistributedCache
  services.AddSession ();
  // Add application services.
  services.AddTransient<IEmailSender, AuthMessageSender> ();
  services.AddTransient<ISmsSender, AuthMessageSender> ();

  services.AddScoped<IRepository, Repository> ();
  services.AddScoped<Context, Context> ();

  services.AddScoped<IAccountBilling, AccountBilling> ();

  services.Configure<AdministratorEmailAddress> (Configuration);
  services.Configure<AuthMessageSenderOptions> (Configuration);
  services.Configure<TBCPaymentOptions> (Configuration);
  services.AddScoped<ViewRender, ViewRender> ();
  services.AddSingleton<IHttpContextAccessor, HttpContextAccessor> ();
  services.Configure<RequestLocalizationOptions> (opts => {
    var supportedCultures = new [] {
    new CultureInfo ("en"),
    new CultureInfo ("ka"),
    new CultureInfo ("ru")
    };

    opts.DefaultRequestCulture = new RequestCulture ("ka");
    // Formatting numbers, dates, etc.
    opts.SupportedCultures = supportedCultures;
    // UI strings that we have localized.
    opts.SupportedUICultures = supportedCultures;
  });

  // Add converter to DI
  //services.AddSingleton(typeof(IConverter), new BasicConverter(new PdfTools()));
  services.AddSingleton<ITemplateService, TemplateService> ();
  services.AddSingleton (typeof (IConverter), new SynchronizedConverter (new PdfTools ()));
  services.AddScoped<MailComposer> ();

}

// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure (IApplicationBuilder app, IHostingEnvironment env) {

  if (env.IsDevelopment ()) {
    app.UseDeveloperExceptionPage ();
    app.UseDatabaseErrorPage ();
  } else {
    app.UseStatusCodePagesWithReExecute ("/Error/{0}");
  }

  app.UseStaticFiles ();

  app.UseAuthentication ();

  app.UseForwardedHeaders (new ForwardedHeadersOptions {
    ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto
  });

  var options = app.ApplicationServices.GetService<IOptions<RequestLocalizationOptions>> ();
  app.UseRequestLocalization (options.Value);

  app.UseSession ();

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

  app.UseHangfireDashboard ();
  app.UseHangfireServer ();
  RecurringJob.AddOrUpdate<IAccountBilling> (a => a.CheckUserPayment (), Cron.Minutely);
  RecurringJob.AddOrUpdate<IAccountBilling> ("CalculateUserCharge", a => a.CalculateUserCharge (DateTime.Today.AddDays (-1)), Cron.Daily (21, 00), TimeZoneInfo.Utc);
  //RecurringJob.AddOrUpdate<IAccountBilling>("CalculateUserCharge",a=>a.CalculateUserCharge(DateTime.Today.AddDays(-1)),Cron.Minutely);

  app.UseMvc (routes => {
    routes.MapRoute (
      name: "default",
      template: "{controller=Home}/{action=Index}/{id?}");
  });
}

} }

HangfireAuthorization.cs

public class HangFireAuthorization: IDashboardAuthorizationFilter{

public bool Authorize([NotNull] DashboardContext context)
{
    return context.GetHttpContext().User.IsInRole("Administrator");
}

}

如何访问hangfire 仪表板?

【问题讨论】:

  • 调试您的代码以检查statusCode 的值是多少?与我们分享您的 vs 输出窗口中的内容。有任何错误信息吗?注释掉这行app.UseStatusCodePagesWithRedirects("/StatusCode?code={0}");并使用app.UseDeveloperExceptionPage();查看详细的错误信息。
  • @TaoZhou 在注释掉 UseStatusCodePagesWithRedirects 之前,我在控制器中放置了一个断点。我得到的 statusCode 是 403。我没有该代码的任何特定视图,所以它转到 IActionResult 的视图。当我注释掉你的建议时,它只是说我没有访问该页面的授权。
  • 与我们分享您当前的Startup.cs。您是否在项目中启用了任何安全架构?
  • @TaoZhou 我编写了自定义授权过滤器,它工作正常。我只是好奇为什么当我应该可以访问仪表板时它会引发错误。 app.UseHangfireDashboard();不工作。然而,app.UseHangfireDashboard("/hangfire", new DashboardOptions { Authorization = new [] { new HangFireAuthorization () } });工作。我将发布整个 startup.cs
  • HangFireAuthorization 是您自己的继承自 IDashboardAuthorizationFilter 的实现吗?

标签: c# asp.net-core


【解决方案1】:

对于Hangfire Dashboard,它会公开有关您的后台作业的敏感信息,包括方法名称和序列化参数,并让您有机会通过执行不同的操作来管理它们——重试、删除、触发等。所以它真的对限制对仪表板的访问很重要。

为了使其安全,默认情况下只允许本地请求,但是您可以通过传递您自己的 IDashboardAuthorizationFilter 接口实现来更改此设置,该接口的 Authorize 方法用于允许或禁止请求。第一步是提供您自己的实现。

参考Configuring Authorization

更新:

对于这种行为,如上所述,并由HangfireApplicationBuilderExtensions 控制。它注册了LocalRequestsOnlyAuthorizationFilter

如果要启用对非本地主机的请求,则需要提供DashboardOptions

【讨论】:

  • 如果我把 app.UseHangfireDashboard();在 UseAuthentication 下面,我得到 403 错误。如果在 UseAuthentication 之前,我会收到 401 错误。
  • @GugaTodua 检查我的更新。这是由 hangfire 库控制的。
【解决方案2】:

仔细检查此代码,看看它是否正确配置

public void ConfigureServices(IServiceCollection services)
{
    // Add Hangfire services.
    services.AddHangfire(configuration => configuration
        .SetDataCompatibilityLevel(CompatibilityLevel.Version_170)
        .UseSimpleAssemblyNameTypeSerializer()
        .UseRecommendedSerializerSettings()
        .UseSqlServerStorage(Configuration.GetConnectionString("HangfireConnection"), new SqlServerStorageOptions
        {
            CommandBatchMaxTimeout = TimeSpan.FromMinutes(5),
            SlidingInvisibilityTimeout = TimeSpan.FromMinutes(5),
            QueuePollInterval = TimeSpan.Zero,
            UseRecommendedIsolationLevel = true,
            UsePageLocksOnDequeue = true,
            DisableGlobalLocks = true
        }));

    // Add the processing server as IHostedService
    services.AddHangfireServer();

    // Add framework services.
    services.AddMvc();
}

public void Configure(IApplicationBuilder app, IBackgroundJobClient backgroundJobs, IHostingEnvironment env)
{
    // ...
    app.UseStaticFiles();

    app.UseHangfireDashboard();
    backgroundJobs.Enqueue(() => Console.WriteLine("Hello world from Hangfire!"));

    app.UseMvc(routes =>
    {
        routes.MapRoute(
            name: "default",
            template: "{controller=Home}/{action=Index}/{id?}");
    });
}

你也不需要像这样的hangfire url

app.UseHangfireDashboard("/hangfire");    

只需使用

app.UseHangfireDashboard();

因为文档已经说过here

应用程序启动时,打开以下 URL(假设您的应用程序 在 5000 端口上运行)以访问 Hangfire 仪表板 界面。如我们所见,我们的后台工作已经完成 成功。

http://localhost:5000/hangfire

【讨论】:

  • 我正在使用 pgSQL。 UseSqlServer 不适合,所以我使用了 UsePostgresqlStorage 并收到错误说 IGlobalConfiguration 没有 UsePostgresqlStorage。
猜你喜欢
  • 1970-01-01
  • 2020-08-02
  • 2016-12-08
  • 2018-08-25
  • 2016-03-27
  • 2017-03-04
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多