我正在开发一种“通知观察者”服务,该服务使用 SignalR 从 Angular 应用程序收集连接的用户(该应用程序使用 Azure Entra 作为身份验证)。此“观察者”服务将检测(通过服务总线或对集线器的调用)其他应用程序已为特定的用户 ID 组(Entra 用户 ID 列表,即 GUID)创建了新通知,然后如果这些特定用户连接到 Hub 实例,它应该能够仅向这些特定用户发送此通知。
问题是,我真的不知道这是否可行,我知道您可以将 SignalR 配置为需要使用 Azure Entra 进行身份验证,但我正在努力查找有关 SignalR 是否可以通过 Azure Entra 区分这些连接用户的信息ID,类似:
foreach(var entraUserId in notification.Users)
await this.hubContext.Client(entraUserId).SendAsync(message);
或者,如果我必须做一些特别的事情,我知道 .Client() 需要一个 connectionId 映射到特定连接,但我感觉有一个我不知道的链接能够将 Entra 用户 ID 映射到 connectionId。
要通过用户 ID(与 Azure AD objectId 相关)获取连接,您必须自己创建和维护用户和连接之间的映射。您可以通过向 OnConnected 和 OnDisconnected 事件添加替代来实现此目的,如下所示:
public class ChatHub : Hub
{
private readonly static Dictionary<string, string> _connections = new Dictionary<string, string>();
public override Task OnConnectedAsync()
{
var userId = Context.UserIdentifier; // This should be objectId GUID
var connectionId = Context.ConnectionId;
// Add the connection ID and user ID to the mapping
lock (_connections)
{
if (!_connections.ContainsKey(userId))
{
_connections[userId] = connectionId;
}
else
{
_connections[userId] = connectionId;
}
}
return base.OnConnectedAsync();
}
public override Task OnDisconnectedAsync(Exception exception)
{
var userId = Context.UserIdentifier;
// Remove the connection ID and user ID from the mapping
lock (_connections)
{
if (_connections.ContainsKey(userId))
{
_connections.Remove(userId);
}
}
return base.OnDisconnectedAsync(exception);
}
public async Task SendNotificationToUser(string userId, string message)
{
// Retrieve the connection ID for the specified user
if (_connections.TryGetValue(userId, out var connectionId))
{
// Send the notification to the specified user's connection
await Clients.Client(connectionId).SendAsync("ReceiveNotification", message);
}
else
{
// Code to handle instances where user is not found.
// Log or ignore, I guess.
}
}
}