Upgrade to ASP.NET Core 2.0 authentication not working for Hangfire.AspNetCore Dashboard
#1,039 建立於 2017年11月3日
描述
Since upgrading to core 2.0, authentication has stopped working for the hangfire dashboard.
The implementation of the Authorize method, now may return false, despite being logged in. This means that calls to eg. /hangfire no longer works in some instances.
public class HangfireDashboardAuthorizationFilter : IDashboardAuthorizationFilter
{
public bool Authorize(DashboardContext context)
{
var httpContext = context.GetHttpContext();
return httpContext.User.Identity.IsAuthenticated;
}
}
This is due to changes introduced with asp.net core 2.0 authentication and supporting multiple authentication schemes. Discussions with the author of the excellent Basic Authentication package Odachi.AspNetCore.Authentication.Basic proposed a solution, found here: https://github.com/Kukkimonsuta/Odachi/issues/11 . This highlights the problem issue and solution very clearly.
As a workaround, I have implemented our own UseHangfireDashboard method. Below is the code for anyone else struggling in this regard, until a fix is in place.
private IApplicationBuilder UseHangfireDashboard(IApplicationBuilder app, string pathMatch = "/hangfire", DashboardOptions options = null, JobStorage storage = null)
{
var services = app.ApplicationServices;
storage = storage ?? services.GetRequiredService<JobStorage>();
options = options ?? services.GetService<DashboardOptions>() ?? new DashboardOptions();
var routes = app.ApplicationServices.GetRequiredService<RouteCollection>();
// Use our custom middleware.
app.Map(new PathString(pathMatch), x => x.UseMiddleware<HangfireDashboardMiddleware>(storage, options, routes));
return app;
}
The middleware created to fix this issue is below. Feel free to use this, although some of the null and config checks are missing from your original source.
This would replace the code here: https://github.com/HangfireIO/Hangfire/blob/master/src/Hangfire.AspNetCore/Dashboard/AspNetCoreDashboardMiddleware.cs
public class HangfireDashboardMiddleware
{
private readonly RequestDelegate nextRequestDelegate;
private readonly JobStorage jobStorage;
private readonly DashboardOptions dashboardOptions;
private readonly RouteCollection routeCollection;
public HangfireDashboardMiddleware(RequestDelegate nextRequestDelegate, JobStorage storage, DashboardOptions options, RouteCollection routes)
{
this.nextRequestDelegate = nextRequestDelegate;
this.jobStorage = storage;
this.dashboardOptions = options;
this.routeCollection = routes;
}
public async Task Invoke(HttpContext httpContext)
{
var aspNetCoreDashboardContext = new AspNetCoreDashboardContext(this.jobStorage, this.dashboardOptions, httpContext);
var findResult = this.routeCollection.FindDispatcher(httpContext.Request.Path.Value);
if (findResult == null)
{
await this.nextRequestDelegate.Invoke(httpContext);
return;
}
// attempt to authenticate against default auth scheme (this will attempt to authenticate using data in request, but doesn't send challenge)
var result = await httpContext.AuthenticateAsync();
if (httpContext.User.Identity.IsAuthenticated == false)
{
// request was not authenticated, send challenge and do not continue processing this request
await httpContext.ChallengeAsync();
}
foreach (var filter in this.dashboardOptions.Authorization)
{
if (filter.Authorize(aspNetCoreDashboardContext) == false)
{
var isAuthenticated = httpContext.User?.Identity?.IsAuthenticated;
httpContext.Response.StatusCode = isAuthenticated == true ? (int)HttpStatusCode.Forbidden : (int)HttpStatusCode.Unauthorized;
return;
}
}
aspNetCoreDashboardContext.UriMatch = findResult.Item2;
await findResult.Item1.Dispatch(aspNetCoreDashboardContext);
}
}
Hope that helps and any questions, please feel free to ask.