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

如何认证Angular应用发往Azure Function(negotiate)端点的请求

Angular对接AAD鉴权访问Azure Function SignalR negotiate端点实现方案

核心逻辑:你已经完成Angular端的Azure AD身份认证,只需要在客户端发起negotiate请求时携带AAD颁发的、受众为Azure Function的有效访问令牌,在Function端前置校验令牌合法性后再返回SignalR连接凭证即可,你之前配置的Function与Azure SignalR服务之间的密钥鉴权逻辑完全不需要改动,不影响内部通信链路。


一、Angular端改造(携带AAD令牌发起negotiate请求)

如果你是用@azure/msal-angular做的AAD认证,按以下两步改:

  • 先调整MSAL配置,在protectedResourceMap中添加你的Azure Function域名,关联Function对应应用注册暴露的委托权限(通常是api://<Function对应AAD应用注册客户端ID>/user_impersonation),确保MSAL拦截器能识别到发往Function的请求需要获取对应资源的访问令牌,不要错拿成Microsoft Graph的令牌。
  • 初始化SignalR客户端连接时,通过SDK自带的accessTokenFactory注入获取到的AAD访问令牌,SDK会自动把令牌放到negotiate请求的Authorization请求头中,不需要额外写HttpClient拦截逻辑,参考可直接运行的代码:
import { HubConnectionBuilder, HttpTransportType } from '@microsoft/signalr';
import { MsalService } from '@azure/msal-angular';

// 在需要初始化SignalR的组件/服务中注入MsalService
private async initSignalR() {
  // 静默获取针对Azure Function资源的有效访问令牌
  const tokenResult = await this.msalService.acquireTokenSilent({
    scopes: ['api://<替换为你Function对应AAD应用的客户端ID>/user_impersonation'],
    account: this.msalService.instance.getActiveAccount()
  }).toPromise();

  // 构建SignalR连接
  this.hubConnection = new HubConnectionBuilder()
    .withUrl('https://<替换为你的Function应用域名>/api/negotiate', {
      transport: HttpTransportType.WebSockets,
      // 核心配置:返回的令牌会自动附加到negotiate请求的鉴权头
      accessTokenFactory: () => tokenResult.accessToken
    })
    .withAutomaticReconnect()
    .build();

  await this.hubConnection.start();
}

注意:本地调试时如果遇到令牌获取失败,先确认当前登录的AAD账号已经给对应API权限做了管理员同意,避免权限不足拿不到令牌。


二、Azure Function端配置(校验AAD令牌+返回SignalR凭证)

不要自己手写JWT验签代码,直接用Azure App Service自带的内置身份验证(Easy Auth)做前置鉴权,配置步骤如下:

  • 打开Azure Portal找到你的Function应用,在左侧菜单找到「身份验证」选项,添加Microsoft身份提供者,选择和Angular应用同一个AAD租户下的对应应用注册,配置未认证请求的响应规则为「返回401未授权」,保存配置即可。这层鉴权在Function的前置网关层执行,会自动完成令牌签名校验、过期校验、受众校验,非法请求直接拦截,不会进到你的函数代码。
  • 修改negotiate函数的代码,从请求头中读取鉴权通过后自动注入的用户唯一标识,传给SignalR服务生成连接凭证,C#函数参考代码:
[FunctionName("negotiate")]
public static SignalRConnectionInfo Run(
    [HttpTrigger(AuthorizationLevel.Anonymous, "post")] HttpRequest req,
    [SignalRConnectionInfo(
        HubName = "<替换为你的SignalR Hub名称>", 
        UserId = "{headers.x-ms-client-principal-id}"
    )] SignalRConnectionInfo connectionInfo)
{
    // 能进到这里的请求都是已经通过AAD鉴权的合法请求
    // x-ms-client-principal-id是Easy Auth校验通过后自动注入的请求头,对应当前登录用户在AAD中的唯一对象ID
    return connectionInfo;
}

关键配置:函数的AuthorizationLevel必须设为Anonymous,因为鉴权已经交给前置的Easy Auth处理,不要用Function自带的主机密钥/函数密钥做鉴权,避免和AAD令牌鉴权逻辑冲突。

  • 最后配置Function的CORS规则,把Angular应用的部署域名(本地调试时加上http://localhost:4200这类本地地址)加到允许的源列表中,打开「允许凭据传输」开关,保存后重启Function即可。

三、常见问题排查

  • negotiate请求返回401:先打开浏览器F12看请求头是否携带Authorization: Bearer <token>,把令牌复制到JWT解析工具查看aud(受众)字段,必须和你Function对应AAD应用的应用ID URI/客户端ID完全一致,不一致就是MSAL的权限范围配置错误,拿到了其他资源的令牌。
  • negotiate请求返回跨域错误:检查CORS配置里是否加了Angular的源地址,不要用通配符*,通配符配置下不允许携带凭据,会被浏览器拦截。
  • 连接成功但收不到点对点消息:检查negotiate函数里传入SignalR的UserId是否和你发送消息时指定的接收方UserId一致,建议统一用AAD返回的用户对象ID作为唯一标识,避免标识不匹配。

内容的提问来源于stack exchange,提问作者santosh kumar patro

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 22:42:18