ABP 6.0.3关闭浏览器后HangFire Dashboard出现401错误求助
问题原因
- Token存储与传递差异:ABP Angular默认将token存在
localStorage中,前端路由请求会自动携带Authorization头,但访问HangFire Dashboard这类后端直接暴露的页面时,浏览器发起的是独立GET请求,不会自动从localStorage读取并携带token,导致HangFire验证无有效凭证。 - 登录态同步问题:关闭浏览器重进ABP应用时,前端通过
localStorage的刷新令牌自动获取新的access token,但这个token未同步到HangFire验证依赖的存储(比如Cookie);重新登录时ABP会将token写入Cookie,此时HangFire能获取到有效凭证,验证通过。 - HangFire验证未适配ABP续期逻辑:ABP前端会自动续期access token,但HangFire的验证中间件未感知新token,旧token过期后就返回401。
解决方法
方法一:URL传递token并验证
后端配置
自定义HangFire授权过滤器,支持从URL参数读取token并通过ABP策略验证:
public class AbpHangFireAuthorizationFilter : IDashboardAuthorizationFilter { private readonly string _policyName; private readonly IAuthorizationService _authorizationService; private readonly IHttpContextAccessor _httpContextAccessor; public AbpHangFireAuthorizationFilter(string policyName, IAuthorizationService authorizationService, IHttpContextAccessor httpContextAccessor) { _policyName = policyName; _authorizationService = authorizationService; _httpContextAccessor = httpContextAccessor; } public async Task<bool> AuthorizeAsync(DashboardContext context) { var httpContext = _httpContextAccessor.HttpContext; // 从URL参数获取token并写入请求头 var token = context.Request.Query["access_token"].FirstOrDefault(); if (!string.IsNullOrEmpty(token)) { httpContext.Request.Headers.Append("Authorization", $"Bearer {token}"); } // 验证ABP授权策略 var result = await _authorizationService.AuthorizeAsync(httpContext.User, null, _policyName); return result.Succeeded; } }
在Program.cs中配置HangFire Dashboard使用该过滤器:
app.UseHangfireDashboard("/hangfire", new DashboardOptions { Authorization = new[] { new AbpHangFireAuthorizationFilter("AbpIdentity.Admin", app.Services.GetRequiredService<IAuthorizationService>(), app.Services.GetRequiredService<IHttpContextAccessor>()) }, IgnoreAntiforgeryToken = true });
前端配置
跳转HangFire时从ABP AuthService获取当前有效token,作为URL参数传递:
import { AuthService } from '@abp/ng.core'; async navigateToHangFire() { const token = await this.authService.getAccessToken(); window.open(`/hangfire?access_token=${token}`, '_blank'); }
方法二:将token同步到Cookie
修改Angular配置,让ABP将token同时写入Cookie,访问HangFire时浏览器自动携带:
前端配置
在environment.ts的oAuthConfig中添加Cookie存储配置:
export const environment = { // ...其他配置 oAuthConfig: { issuer: 'https://your-domain.com', redirectUri: window.location.origin, clientId: 'YourAngularClientId', responseType: 'code', scope: 'offline_access YourApiScope', storeAuthStateInCookie: true // 开启Cookie存储token } };
后端配置
确保HangFire使用Cookie验证策略:
app.UseAuthentication(); app.UseAuthorization(); app.UseHangfireDashboard("/hangfire", new DashboardOptions { Authorization = new[] { new AuthorizationPolicyFilter(new AuthorizationPolicyBuilder() .RequireAuthenticatedUser() .Build()) } });
方法三:让HangFire复用ABP Bearer验证
将HangFire中间件放在ABP验证中间件之后,确保请求经过Bearer验证:
app.UseAuthentication(); app.UseAuthorization(); app.UseOpenIddictValidation(); // 启用OpenIddict验证 app.UseHangfireDashboard("/hangfire", new DashboardOptions { Authorization = new[] { new AuthorizationPolicyFilter(new AuthorizationPolicyBuilder() .AddAuthenticationSchemes(JwtBearerDefaults.AuthenticationScheme) .RequireAuthenticatedUser() .Build()) } });
内容的提问来源于stack exchange,提问作者Jerry
相关产品推荐
相关产品推荐

