如何认证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
相关产品推荐
相关产品推荐

