如何用IdentityServer4认证SignalR客户端?遇403/401错误求助
SignalR连接IdentityServer认证失败(403/401)排查
问题场景
我通过IdentityServer(地址http://localhost:5006)获取Token,客户端代码如下:
var httpClient = new HttpClient(); var discoveryDocument = httpClient.GetDiscoveryDocumentAsync("http://localhost:5006").Result; var tokenResponse = httpClient.RequestClientCredentialsTokenAsync( new ClientCredentialsTokenRequest { Address = discoveryDocument.TokenEndpoint, ClientId = "client", ClientSecret = "Prevo100", Scope = "prevo100-api" }).Result;
尝试连接SignalR Hub(地址http://localhost:5119/Prevo100)时,调用StartAsync()抛出异常:
System.AggregateException : 'One or more errors occurred. (Response status code does not indicate success: 403 (Forbidden).)'
偶尔也会出现401错误。SignalR客户端连接代码:
var url = "http://localhost:5119/Prevo100"; HubConnection connection = new HubConnectionBuilder() .WithUrl(url, options => { options.AccessTokenProvider = () => Task.FromResult(tokenResponse.AccessToken); }) .WithAutomaticReconnect() .Build(); var client = new Prevo100WebClient(connection); connection.StartAsync().Wait(); // <== 异常发生在此处
服务器端配置
SignalR Hub所在服务器的配置代码:
public void ConfigureServices(IServiceCollection services) { services.AddAuthentication("Bearer") .AddJwtBearer("Bearer", options => { options.Authority = "http://localhost:5006"; options.RequireHttpsMetadata = false; options.Audience = "prevo100-api"; options.TokenValidationParameters = new Microsoft.IdentityModel.Tokens.TokenValidationParameters { ValidateAudience = false }; 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("/Prevo100")) { context.Token = accessToken; } return Task.CompletedTask; } }; }); services.AddSignalR(hubOptions => { //hubOptions.ClientTimeoutInterval // 30 secondes par défaut }); } public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } app.UseHttpsRedirection(); app.UseStaticFiles(); app.UseFileServer(); app.UseRouting(); app.UseAuthentication(); app.UseAuthorization(); app.UseEndpoints(endpoints => { endpoints.MapHub<Prevo100Hub>("/Prevo100"); }); }
Hub类添加了授权特性:
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)] public class Prevo100Hub : Hub<IPrevo100Client>, IHubContract { //.... }
请求帮忙排查认证失败导致的403/401错误原因。
排查步骤
1. 验证Token有效性
- 先确认
tokenResponse.IsError是否为false,如果是true,查看tokenResponse.Error字段获取具体错误 - 将
tokenResponse.AccessToken用JWT解析工具查看:- 确认
iss字段为http://localhost:5006 - 确认
scope包含prevo100-api - 检查
exp字段,确认Token未过期
- 确认
2. 检查Token传递与提取逻辑
- 在客户端连接前打印
tokenResponse.AccessToken,确保不是空值或无效值 - 在服务器的
OnMessageReceived事件中添加日志,打印accessToken和path,确认是否能正确获取到Token
3. 修正认证配置冲突
服务器配置中同时设置了options.Audience = "prevo100-api"和ValidateAudience = false,二者冲突:
- 若需验证Audience,删除
ValidateAudience = false,确保Token的aud包含prevo100-api - 若无需验证Audience,删除
options.Audience = "prevo100-api",避免冗余配置
4. 确认IdentityServer客户端配置
检查IdentityServer中client客户端的配置项:
- 确保
AllowedGrantTypes包含client_credentials - 确保
AllowedScopes包含prevo100-api - 确保
ClientSecrets中存在Prevo100(注意大小写和格式匹配)
5. 检查中间件与协议影响
- 服务器启用了
UseHttpsRedirection,但客户端用http连接,可能导致重定向时丢失Token,开发环境可临时注释该中间件测试 - 确认SignalR使用的传输协议(WebSocket/SSE)是否触发了
OnMessageReceived逻辑,可在日志中打印请求的传输类型
6. 隔离授权环节验证
- 临时去掉Hub类的
[Authorize]特性,测试是否能正常连接,以此确认是否是授权规则导致的问题 - 若去掉后能连接,检查
[Authorize]是否包含角色、声明等额外限制,确保Token中包含对应内容
内容的提问来源于stack exchange,提问作者Aminos
相关产品推荐
相关产品推荐

