You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Azure SignalR对接Xamarin时NegotiateAsync返回401未授权问题

问题:SignalR /negotiate 请求返回401未授权(Azure SignalR 集成场景)

环境与配置

服务器端配置(.NET 6)

public void ConfigureServices(IServiceCollection services)
{
    services.AddSignalR(options => {
                options.EnableDetailedErrors = true;
            })
            .AddAzureSignalR(options =>
            {
                options.InitialHubServerConnectionCount = 1;
                options.ConnectionString = "xxxx"

            });
}

protected virtual void ConfigureAuthentication(IServiceCollection services)
{
    services
        .AddAuthentication(options =>
        {
            options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
        })
        .AddJwtBearer(options =>
        {
            options.Authority = $"{AzureB2CConfig.Instance}/{AzureB2CConfig.Domain}/{AzureB2CConfig.SignUpSignInPolicyId}/v2.0/";
            options.Audience = AzureB2CConfig.Audience;

            options.Events = new JwtBearerEvents
            {
                OnMessageReceived = context =>
                {
                    var authToken = context.Request.Headers["Authorization"].ToString().Replace("Bearer ", "");

                    var path = context.HttpContext.Request.Path;
                    if (!string.IsNullOrEmpty(authToken) &&
                        (path.StartsWithSegments("/myhubs")))
                    {
                        context.Token = authToken;
                    }

                    return Task.CompletedTask;
                }
            };

            options.TokenValidationParameters =
                new TokenValidationParameters
                {
                    LifetimeValidator = (before, expires, token, param) =>
                    {
                        return expires > DateTime.UtcNow;
                    },
                    ValidateAudience = false,
                    ValidateIssuer = false,
                    ValidateActor = false,
                    ValidateLifetime = true,
                    ValidateIssuerSigningKey = false
                };
        });

    services.AddAuthorization(options =>
    {
        options.AddPolicy("AllowedUser", policy =>
        {
            policy.Requirements.Add(new AllowedUserRequirement());
        });
    });

}

public void Configure(IApplicationBuilder app)
{

    app.UseAuthentication();
    app.UseAuthorization();

    app.UseFileServer();
    app.UseEndpoints(routes =>
    {
        routes.MapHub<MyHub>("/myhubs");
        
    });

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapControllers();
    });
}

客户端配置

var connection = new HubConnectionBuilder()
  .WithUrl(SignalRServerUrl, options =>
  {
      options.AccessTokenProvider = authenticationService.GetAccessToken; // 返回有效的访问令牌
  })
  .WithAutomaticReconnect()
  .Build();

 await Policy
     .Handle<Exception>()
     .WaitAndRetryAsync(1, x => TimeSpan.FromMilliseconds(500))
     .ExecuteAsync(() => _connection.StartAsync()); // 触发401未授权错误

问题描述

/negotiate请求返回401(未授权),尝试多种方案并查阅相关技术文章均未解决,框架版本为.NET 6。

2022年10月20日更新:添加services.AddAuthorization()配置后,应用与自建服务器之间的认证已成功,但应用与Azure SignalR服务之间的认证仍失败,返回401未授权。询问是否存在缺失配置。


解决方案

针对Azure SignalR与客户端间的401问题,需检查以下关键配置点:

1. 验证Azure SignalR连接字符串有效性

确认options.ConnectionString中的值是从Azure Portal获取的完整有效连接字符串,包含正确的Endpoint和Access Key,避免因密钥错误或格式问题导致服务端无法与Azure SignalR建立信任连接。

2. 为Hub绑定授权策略

已定义AllowedUser策略,但未将其应用到Hub实例上。需在Hub类添加特性,强制仅符合策略的用户可访问:

[Authorize(Policy = "AllowedUser")]
public class MyHub : Hub
{
    // Hub业务方法实现
}

3. 优化JWT认证的Token获取逻辑

SignalR客户端默认会通过QueryString的access_token参数传递令牌,而非仅依赖Authorization头。需调整OnMessageReceived事件处理逻辑,同时支持两种传递方式:

OnMessageReceived = context =>
{
    // 同时处理QueryString和Header中的令牌
    var token = context.Request.Query["access_token"].FirstOrDefault();
    if (string.IsNullOrEmpty(token))
    {
        token = context.Request.Headers["Authorization"].ToString().Replace("Bearer ", "");
    }

    var path = context.HttpContext.Request.Path;
    if (!string.IsNullOrEmpty(token) && path.StartsWithSegments("/myhubs"))
    {
        context.Token = token;
    }

    return Task.CompletedTask;
}

4. 确认客户端Token的有效性

使用JWT解析工具(如jwt.io)验证authenticationService.GetAccessToken()返回的令牌:

  • 检查exp声明,确保令牌未过期
  • 确认令牌包含的声明满足AllowedUser策略的验证要求
  • 确保令牌能被服务器端的JWT验证逻辑通过

5. 检查中间件顺序

当前Configure方法中UseAuthentication()和UseAuthorization()已置于UseEndpoints之前,此顺序正确,无需调整,但需避免其他自定义中间件干扰认证流程。


内容的提问来源于stack exchange,提问作者Takeo Nishioka

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.16 10:45:43