SignalR匿名用户连接持久化及多标签消息同步方案咨询
Great question! For anonymous users, since we don’t have a built-in identity like Context.User.Identity.Name to use as a group key, we need to create a unique, persistent identifier that sticks across page reloads and multiple tabs. Here’s a straightforward approach that mirrors your logged-in user implementation:
Step 1: Generate & Store an Anonymous User ID on the Client
We’ll use the browser’s localStorage (which persists across sessions and tabs) to create and store a unique ID for each anonymous visitor. This ID will be sent to the SignalR hub every time a connection is established.
// Get or generate an anonymous user ID let anonymousUserId = localStorage.getItem('anonymousUserId'); if (!anonymousUserId) { // Use crypto.randomUUID() for modern browsers (fall back to a custom UUID generator if needed) anonymousUserId = crypto.randomUUID(); localStorage.setItem('anonymousUserId', anonymousUserId); } // Initialize SignalR connection with the anonymous ID as a query parameter const connection = new signalR.HubConnectionBuilder() .withUrl('/chatHub', { queryParams: { anonymousUserId: anonymousUserId } }) .build(); // Start the connection (add error handling as needed) connection.start().catch(err => console.error(err.toString()));
Step 2: Add Anonymous Connections to a User-Specific Group on the Server
In your SignalR hub’s OnConnectedAsync method, retrieve the anonymous ID from the query parameters and add the current connection to a group named after this ID. This mirrors how you handle logged-in users with their username.
public override async Task OnConnectedAsync() { // Handle authenticated users as you already do if (Context.User.Identity.IsAuthenticated) { var userName = Context.User.Identity.Name; await Groups.AddAsync(Context.ConnectionId, userName); } // Handle anonymous users else { if (Context.GetHttpContext().Request.Query.TryGetValue("anonymousUserId", out var anonymousUserId)) { // Optional: Add a prefix like "anon_" to avoid collisions with usernames var groupName = $"anon_{anonymousUserId}"; await Groups.AddAsync(Context.ConnectionId, groupName); } } await base.OnConnectedAsync(); }
Step 3: Send Messages to the User’s Group
When you need to send a message to a specific user (whether logged-in or anonymous), target their group directly. All active connections (across tabs or after page reloads) belonging to that user will receive the message.
// Example: Send a message to a specific user public async Task SendMessageToUser(string targetGroupId, string messageContent) { await Clients.Group(targetGroupId).SendAsync("ReceiveMessage", messageContent); }
Key Notes
- Persistence:
localStoragekeeps the anonymous ID even if the user closes the browser and returns later. If you want the ID to expire when the browser closes, usesessionStorageinstead (but it won’t share across tabs). - Collision Prevention: Adding a prefix like
"anon_"to the anonymous group name ensures it won’t clash with valid usernames from your authenticated users. - Cleanup: SignalR automatically removes connections from groups when they disconnect, so you don’t need to handle that manually. For long-abandoned anonymous groups, you could add a background job to clean them up, but this is usually unnecessary for most use cases.
内容的提问来源于stack exchange,提问作者d1cte

