如何在EventGrid触发的Azure Function事件中获取User ID
我有一个基于.NET7独立工作进程的EventGrid触发Azure Function,每当客户端连接SignalR hub时会被调用,代码如下:
[Function("v1-on-connectivity-events-changed")] public async Task OnConnectivityEventsChangedAsync ( [EventGridTrigger] EventGridConnectivityEvent eventGridConnectivityEvent, FunctionContext functionContext ) { _logger.LogWarning("Event grid trigger received. Data='{ConnectionInfo}'", JsonSerializer.Serialize(eventGridConnectivityEvent)); ... }
客户端通过Negotiate API连接SignalR的代码如下:
_hubConnection = new HubConnectionBuilder() .WithUrl(hubEndpoint.AbsoluteUri, options => { // Adds the application token to the options' header. options.AccessTokenProvider = () => Task.FromResult(user.IdentityToken.AccessToken)!; options.Headers.Add("userSid", user.IdentityToken.UserSid); }) .Build(); ... await _hubConnection.StartAsync();
Negotiate函数返回包含额外参数的URL,代码如下:
[Function("negotiate")] public Task<SignalRConnectionInfo> OnNegotiateAsync ( [HttpTrigger(AuthorizationLevel.Anonymous, "POST")] HttpRequestData httpRequestData, [SignalRConnectionInfoInput ( HubName = Constants.HubName, ConnectionStringSetting = "AzureSignalRConnectionString" )] SignalRConnectionInfo signalRConnectionInfo ) { return ExecuteAsync(httpRequestData, async claimsPrincipal => { IUserPrincipal userPrincipal = await RetrieveClaimsAsync(httpRequestData, claimsPrincipal); signalRConnectionInfo.Url += $"&userSid={userPrincipal.UserSid}"; return signalRConnectionInfo; }); }
客户端连接时,OnConnectivityEventsChangedAsync函数可正常触发,但事件中缺少所需的User ID。根据SignalR文档,连接事件应同时提供User ID和Connection ID,而当前收到的事件数据如下:
{ "Id":"56f3ab25-11d7-41d6-acbb-8429a741d746", "Topic":"/subscriptions/<subscription_id>/resourceGroups/<resource_group>/providers/Microsoft.SignalRService/SignalR/<signalr_instance>", "Subject":"hub/updates", "EventType":"Microsoft.SignalRService.ClientConnectionConnected", "EventTime":"2022-11-27T19:22:19.2349923Z", "Data": { "timestamp":"2022-11-27T19:22:19.2349923Z", "hubName":"updates", "connectionId":"gmJM_GHVkXsQuS5C1LhdXXXXX" } }
请问如何在事件中同时获取User ID和Connection ID?
要让Azure SignalR的Event Grid事件包含User ID,需确保协商阶段正确关联用户标识,而非仅手动拼接URL参数,具体操作如下:
通过
SignalRConnectionInfoInput绑定设置用户标识
修改Negotiate函数的SignalRConnectionInfoInput属性,添加UserId绑定表达式,直接从请求头或令牌声明中获取用户ID。示例中从请求头的userSid字段获取:[SignalRConnectionInfoInput ( HubName = Constants.HubName, ConnectionStringSetting = "AzureSignalRConnectionString", UserId = "{headers.userSid}" )] SignalRConnectionInfo signalRConnectionInfo此操作会让Azure SignalR服务自动将用户ID与连接关联,后续连接事件将携带该字段。
移除手动拼接URL的代码
无需再手动给signalRConnectionInfo.Url追加userSid参数,因为UserId绑定已完成用户标识关联。修改后的Negotiate核心代码如下:[Function("negotiate")] public Task<SignalRConnectionInfo> OnNegotiateAsync ( [HttpTrigger(AuthorizationLevel.Anonymous, "POST")] HttpRequestData httpRequestData, [SignalRConnectionInfoInput ( HubName = Constants.HubName, ConnectionStringSetting = "AzureSignalRConnectionString", UserId = "{headers.userSid}" )] SignalRConnectionInfo signalRConnectionInfo ) { return ExecuteAsync(httpRequestData, async claimsPrincipal => { IUserPrincipal userPrincipal = await RetrieveClaimsAsync(httpRequestData, claimsPrincipal); return signalRConnectionInfo; }); }验证事件数据
完成修改后,客户端重新连接,Event Grid触发的事件数据将新增userId字段,示例如下:{ "Id":"56f3ab25-11d7-41d6-acbb-8429a741d746", "Topic":"/subscriptions/<subscription_id>/resourceGroups/<resource_group>/providers/Microsoft.SignalRService/SignalR/<signalr_instance>", "Subject":"hub/updates", "EventType":"Microsoft.SignalRService.ClientConnectionConnected", "EventTime":"2022-11-27T19:22:19.2349923Z", "Data": { "timestamp":"2022-11-27T19:22:19.2349923Z", "hubName":"updates", "connectionId":"gmJM_GHVkXsQuS5C1LhdXXXXX", "userId":"your-user-sid-value" } }扩展说明
如果用户标识来自JWT令牌的声明,可调整UserId的绑定表达式,例如从令牌的特定声明字段获取,确保Azure SignalR服务能正确关联用户ID与连接。
内容的提问来源于stack exchange,提问作者Kzryzstof

