.NET 8 Blazor Server中JWT令牌注入HTTP请求管道问题求助
.NET 8 Blazor Server中JWT令牌集成到HTTP请求管道的解决方案
问题根源分析
- Refit配置中使用
GetAwaiter().GetResult()同步阻塞异步操作,在Blazor Server的单线程同步上下文下会导致死锁,无法正确获取令牌。 - 委托处理器依赖缓存的
_tokenProvider,没有实时从ProtectedSessionStorage读取最新令牌,可能使用过期或空值。
修正方案
1. 修复Refit的令牌获取逻辑
将同步等待改为异步实现,利用AuthorizationHeaderValueGetter的异步支持:
public RefitService(IHttpClientFactory http, ProtectedSessionStorage sessionStorage) { _client = http.CreateClient(HTTP_CLIENT_KEY); _sessionStorage = sessionStorage; _refitSettings = new(new NewtonsoftJsonContentSerializer()) { AuthorizationHeaderValueGetter = async (request, cancellationToken) => { TokenProvider tokenProvider = await GetTokenProvide(cancellationToken); return tokenProvider.AccessToken; } }; } // 实现支持取消令牌的异步获取方法 private async Task<TokenProvider> GetTokenProvide(CancellationToken cancellationToken) { var result = await _sessionStorage.GetAsync<TokenProvider>("tokenKey", cancellationToken); return result.Success ? result.Value : new TokenProvider(); }
2. 修正委托处理器的实时令牌获取
每次请求时直接从ProtectedSessionStorage读取令牌,避免依赖缓存:
public class JwtAuthorizationHandler : DelegatingHandler { private readonly ProtectedSessionStorage _sessionStorage; public JwtAuthorizationHandler(ProtectedSessionStorage sessionStorage) { _sessionStorage = sessionStorage; } protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) { var tokenResult = await _sessionStorage.GetAsync<TokenProvider>("tokenKey", cancellationToken); if (tokenResult.Success && !string.IsNullOrWhiteSpace(tokenResult.Value.AccessToken)) { // 注意Bearer后面不要加多余空格 request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", tokenResult.Value.AccessToken); } return await base.SendAsync(request, cancellationToken); } }
3. 正确注册委托处理器
在Program.cs中注册处理器并关联到HttpClient:
builder.Services.AddScoped<JwtAuthorizationHandler>(); builder.Services.AddHttpClient(HTTP_CLIENT_KEY) .AddHttpMessageHandler<JwtAuthorizationHandler>();
4. 验证PersistentAuthenticationStateProvider的令牌读取
确保GetTokenProvide方法正确从存储读取令牌:
private async Task<TokenProvider> GetTokenProvide() { var result = await ProtectedSessionStorage.GetAsync<TokenProvider>("tokenKey"); return result.Success ? result.Value : new TokenProvider(); }
关键注意事项
- 绝对避免在Blazor Server中使用
GetAwaiter().GetResult()、Result等同步阻塞异步操作的写法,会触发死锁。 - 确保令牌存储的键名(如示例中的
tokenKey)在存入、读取时完全一致。 - 检查
Bearer头的格式,不要在Bearer和令牌之间添加多余空格。
内容的提问来源于stack exchange,提问作者kyenry
相关产品推荐
相关产品推荐

