c# - 使用 Azure SignalR 向特定用户发送消息

标签 c# azure signalr azure-signalr

使用Azure SignalR(不是.Net Core SignalR),是Clients.Users.SendAsync支持向特定用户发送消息吗?

[Authorize]
public class ChatHub : Hub
{
    public async Task OnNewMessage(string userId, string message)
    {
        await Clients.Users(userId) 
             //Does Azure SignalR supports sending message to specific user,
             // the way .Net Core SignalR does it
            .SendAsync("OnNewMessage", userId, message);
    }
}

If yes, How Asp.Net Identity Claims Principal gets passed to Azure SignalR?

编辑:2021 年 6 月 18 日

以下回复并未解决您的问题。抱歉,我已经遵循了自定义文档 UserIdBasedProvider等等。我想强调的是 -

This question is pertaining to how SignalR handles .Users(<*some-user-id*>).Send();

理想情况下我们会这样做 .Client(<connection id>).Send()向特定用户发送消息。但对于这种架构,我们必须自己将 userId 和 connectionId 存储在数据库等中。

.User(userId).Send()与.Net Core SignalR 完美配合。所以我相信 SignalR SDK 一定在内存中保存了每个连接 ID 和用户 ID 的映射。

Does Azure SignalR internally keeps track of UserId, Connection Id mapping and sends the message?

最佳答案

是的,如果您想实现无服务器架构,您应该使用 Azure Functions。典型的无服务器架构如下所示

azure signalr architecture

客户端(即浏览器)向 azure 函数发送协商请求,响应包含与 Azure SignalR 建立连接所需的所有信息。您应该将 JWT token 附加到协商请求中。如何获取 JWT token 取决于您。附加它非常简单,只需在创建 signalR 连接时提供一个 token 工厂即可

const connection = new signalR.HubConnectionBuilder()
    .withUrl('link to your azure functions api', {
        accessTokenFactory: () => {
            return 'your token'
        }
    })
    .build();

为此,您还需要设置 upstream连接,以便您的 Azure SignalR 服务可以将所有事件转发到您的 Azure Function。 Azure funciton 处理上游事件并向 Azure SignalR 发送请求,以向给定用户或多个用户广播数据。

upstream set up

集线器中的SendMessage方法的代码与常规集线器非常相似,除了Azure函数绑定(bind)之外。您还需要扩展 ServerlessHub 类而不是 Hub 并安装 Microsoft.Azure.WebJobs.Extensions.SignalRService

public class ChatHub : ServerlessHub
{

    [FunctionName(nameof(SendToUser))]
    public async Task SendToUser([SignalRTrigger] InvocationContext invocationContext, string userName, string message)
    {
        await Clients.User(userName).SendAsync("new_message", new NewMessage(invocationContext, message));
    }

    [FunctionName("negotiate")]
    public SignalRConnectionInfo Negotiate([HttpTrigger(AuthorizationLevel.Anonymous)] HttpRequest req)
    {
        var claims = GetClaims(req.Headers["Authorization"]);
        var userName = claims.First(x => x.Type == ClaimTypes.NameIdentifier);
        return Negotiate(userName.Value, claims);
    }


    private class NewMessage
    {
        public string ConnectionId { get; }
        public string Sender { get; }
        public string Text { get; }

        public NewMessage(InvocationContext invocationContext, string message)
        {
            Sender = string.IsNullOrEmpty(invocationContext.UserId) ? string.Empty : invocationContext.UserId;
            ConnectionId = invocationContext.ConnectionId;
            Text = message;
        }
    }
}

您还可以找到包含分步说明的代码示例 here

编辑:

如果您不想完全无服务器并且想使用常规网络应用程序,那也完全没问题。架构图如下所示

Web app architecture

在这种情况下,您应该使用常规的集线器类。您发布的代码应该可以正常工作。

连接管理完全由 Azure Signalr 服务完成,您不需要执行任何额外的同步,也不需要将连接数据存储在数据库中。只需设置层大小和单位数量即可。

以下是其工作原理的简短描述:

  1. 客户端(例如浏览器中的 Js 客户端)将请求发送到 Web 应用程序的 negotiate 端点,并接收指向 azure signalr 服务的链接和访问 token 。这是一个 JWT token 。 JWT token 由几个部分组成。该 token 的第二部分是有效负载,其中包含声明。
  2. 使用从 negotiate 端点客户端获取的数据连接到 azure signalr 服务。

因此,Azure SignalR 服务使用从协商端点接收的此访问 token 来对用户进行身份验证。您不必编写任何额外的代码,因为这一切都是由库在幕后完成的。

如果您使用网络应用,negotiate 请求由 SignalR Sdk 处理,您无需为此编写任何额外代码。

这一切都在this article中有描述。

您可以找到有关实现身份验证的详细指南 here

关于c# - 使用 Azure SignalR 向特定用户发送消息,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67903234/

相关文章:

SQL Server Management Studio 2012 连接到 Azure SQL

asp.net-mvc - SignalR 2.0 - IIS 虚拟目录中的 404

c# - 使用Nest Client进行Elastic Search中的动态构面

c# - 如何获得属性(property)的 setter/getter ?

azure - 刷新所有 Azure 实例上的数据

azure - 如何维护从自定义镜像创建新虚拟机的驱动器映射

azure - Azure SignalR 中的默认/无服务器/经典设置之间有什么区别?

signalr - 重新连接断开连接的 SignalR 客户端 (JS) 的最佳实践

c# - C#中如何将数据复制到剪贴板

c# - 如何使用反 xss 攻击清理 web api 中的输入数据