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

跨应用连接Azure AD认证保护的SignalR集线器授权失败问题

问题核心原因
  • SignalR 2.x 版本的长连接传输(WebSocket、Server-Sent Events)受浏览器标准限制,无法自定义附加请求头。你之前在客户端配置的Authorization、自定义令牌头,仅会在初始/negotiate协商请求中生效,后续建立长连接的请求不会携带这些头,到达App Service认证层时拿不到合法凭证,就会被强制302跳转到AAD登录页。
  • Azure App Service 启用的强制AAD认证(Easy Auth)默认仅从请求头提取令牌,不会主动解析查询字符串中的令牌参数,这也是你之前传头不生效的第二个核心原因。
  • 同站点场景下浏览器会自动携带站点的身份Cookie,所以SignalR能正常走Cookie认证,跨应用场景下不会带这个Cookie,才会暴露认证问题。
分步修复方案

1. 调整App Service认证配置,支持查询参数传令牌

因为长连接无法携带自定义请求头,需要让Easy Auth支持从查询字符串读取令牌做校验:

  • 进入Azure门户对应App Service的「认证」面板,找到已配置的AAD身份提供程序,点击编辑
  • 找到「允许的令牌来源」配置项,勾选Query string选项,保持默认查询参数名access_token即可,保存配置

该配置不会降低站点安全等级:Easy Auth依然会对查询参数中传入的令牌做完整校验,包括签名合法性、过期时间、受众匹配、租户限制等规则,和头传令牌的校验逻辑完全一致。

2. 修正服务端SignalR配置

打开ASP.NET MVC项目的OWIN启动类(一般是Startup.cs),调整SignalR映射和认证逻辑:

public void Configuration(IAppBuilder app)
{
    // 保留你原有的MVC、Web API路由配置
    // 配置SignalR跨域规则,生产环境不要用*通配符,明确填写发起跨站连接的第三方应用域名
    app.Map("/signalr", map =>
    {
        map.UseCors(CorsOptions.AllowAll);
        var hubConfig = new HubConfiguration
        {
            EnableDetailedErrors = false // 生产环境关闭详细错误
        };
        map.RunSignalR(hubConfig);
    });
    // 加中间件拦截SignalR请求的302跳转,避免返回登录页重定向,直接返回401状态码
    app.Use(async (context, next) =>
    {
        await next();
        if (context.Request.Path.StartsWithSegments(new PathString("/signalr")) 
            && context.Response.StatusCode == 302)
        {
            context.Response.StatusCode = 401;
            context.Response.Headers.Remove("Location");
        }
    });
}

3. 调整跨站SignalR客户端的连接逻辑

SignalR 2.0.4版本客户端支持通过qs配置项给所有请求(包括协商、连接、心跳等全生命周期请求)附加查询参数,把AAD令牌放到这个参数里传递即可,JS客户端示例:

// 提前获取针对当前App Service AAD应用申请的有效access_token
// 注意令牌的aud(受众)必须匹配当前App Service绑定的AAD应用标识,不能用其他资源的令牌
const validAadToken = "你的有效AAD访问令牌";
const connection = $.hubConnection("https://你的App Service域名/");
const yourHubProxy = connection.createHubProxy("你的集线器名称");
// 将令牌附加到所有请求的查询参数中
connection.qs = { access_token: validAadToken };
// 跨域场景必须开启凭证传递
connection.start({ withCredentials: true })
    .done(() => {
        console.log("SignalR连接建立成功");
    })
    .fail(err => {
        console.error("连接失败", err);
    });

4. 常见排查点

如果配置后依然连接失败,按顺序核对:

  • 打开浏览器F12网络面板,筛选/signalr/connect请求,确认请求URL携带了access_token参数,响应状态码为101(WebSocket)或200(SSE/长轮询)
  • 解析你使用的AAD令牌,确认aud声明匹配当前App Service绑定的AAD应用ID/应用ID URI,令牌未过期
  • 确认SignalR服务端NuGet包版本和前端jquery.signalR.js版本完全为2.0.4,版本不匹配会导致协商阶段失败
  • 检查App Service认证配置中「请求未经验证时执行的操作」保持为「使用Azure Active Directory登录」即可,不需要修改为匿名访问

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 15:12:24