SignalR Hub加Authorize属性后JWT认证返回401问题排查
问题:Blazor Server结合Identity与SignalR时JWT认证及用户识别异常
我在Blazor Server项目中结合Identity使用SignalR,配置的JWT选项如下:
.AddJwtBearer(options => { options.TokenValidationParameters = new TokenValidationParameters() { ValidateAudience=false, ValidateIssuer=true, ValidateLifetime=true, ValidateIssuerSigningKey=true, ValidIssuer = builder.Configuration["Jwt:Issuer"], ValidAudience=builder.Configuration["Jwt:Audience"], IssuerSigningKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(builder.Configuration["Jwt:Key"])), }; options.Events = new JwtBearerEvents { OnMessageReceived = context => { var accessToken = context.Request.Query["access_token"]; var path = context.HttpContext.Request.Path; if (!string.IsNullOrEmpty(accessToken) && (path.StartsWithSegments("/ConnectionsHub"))) { context.Token = accessToken; context.Response.Headers.Authorization = accessToken; } return Task.CompletedTask; } }; }) ... builder.Services.AddSingleton<IUserIdProvider, NameUserIdProvider>(); builder.Services.AddSingleton<IUserIdProvider, CustomEmailProvider>();
自定义IUserIdProvider代码:
public class CustomEmailProvider : IUserIdProvider { public virtual string GetUserId(HubConnectionContext connection) { var res = connection.User?.Claims.FirstOrDefault(x=>x.Type==ClaimTypes.NameIdentifier); return res?.Value; } }
遇到的问题:
- 当Hub添加
[Authorize]属性时,客户端连接返回401未授权 - 不添加
[Authorize]时,GetUserId返回null,且connection.User无任何Claims,无法识别Identity用户
可能的问题及修复方案
1. 重复注册IUserIdProvider导致服务冲突
同时注册NameUserIdProvider和CustomEmailProvider两个IUserIdProvider实现,DI容器只会保留最后注册的实例。核心问题是认证未通过导致connection.User为空,先移除重复注册,只保留自定义实现:
// 移除 builder.Services.AddSingleton<IUserIdProvider, NameUserIdProvider>(); builder.Services.AddSingleton<IUserIdProvider, CustomEmailProvider>();
2. OnMessageReceived事件错误设置响应头
在事件中设置context.Response.Headers.Authorization属于错误操作,会干扰认证流程,仅需将提取到的令牌赋值给context.Token即可:
options.Events = new JwtBearerEvents { OnMessageReceived = context => { var accessToken = context.Request.Query["access_token"]; var path = context.HttpContext.Request.Path; if (!string.IsNullOrEmpty(accessToken) && path.StartsWithSegments("/ConnectionsHub")) { context.Token = accessToken; } return Task.CompletedTask; } };
3. TokenValidationParameters配置矛盾
设置ValidateAudience=false的同时指定ValidAudience会导致验证逻辑混乱,根据需求二选一:
- 无需验证Audience:移除
ValidAudience赋值ValidateAudience=false, // 去掉 ValidAudience=builder.Configuration["Jwt:Audience"], - 需要验证Audience:将
ValidateAudience设为true,确保配置文件中Jwt:Audience值正确ValidateAudience=true, ValidAudience=builder.Configuration["Jwt:Audience"],
4. 中间件顺序错误
Blazor Server中认证中间件顺序必须正确,确保UseAuthentication和UseAuthorization在UseRouting之后,且在MapBlazorHub和MapHub之前:
app.UseRouting(); app.UseAuthentication(); app.UseAuthorization(); app.MapBlazorHub(); app.MapHub<ConnectionsHub>("/ConnectionsHub"); app.MapFallbackToPage("/_Host");
5. 客户端令牌传递方式不正确
确保SignalR客户端通过AccessTokenProvider将令牌注入到请求查询参数中:
var hubConnection = new HubConnectionBuilder() .WithUrl(NavigationManager.ToAbsoluteUri("/ConnectionsHub"), options => { options.AccessTokenProvider = () => Task.FromResult(yourJwtToken); }) .Build();
内容的提问来源于stack exchange,提问作者PontiacGTX
相关产品推荐
相关产品推荐

