How to persist SignalR connection ID

2020-07-22 09:50发布

问题:

I’m trying to build a chat apps whereby users id are represented by their auto generated signalR connection id. On page refresh, the connection id changes when a new connection is instantiated. Is there a way to persist the state of the connection id of a user until the browser session is ended (i.e until he ends his session on client).

Any guide or documentation? It really would help.

i am new in signalr. so trying to know many things searching Google. from this url i got a similar snippet http://kevgriffin.com/maintaining-signalr-connectionids-across-page-instances/

they are saying it is possible. the problem is signalr often create a new connection id if we referesh the page. i want to prevent this but how.......

this code snippet.

public class MyConnectionFactory : IConnectionIdFactory
    {
        public string CreateConnectionId(IRequest request)
        {
            if (request.Cookies["srconnectionid"] != null)
            {
                return request.Cookies["srconnectionid"];
            }

            return Guid.NewGuid().ToString();
        }
    }

$.connection.hub.start().done(function () {
        alert("Connected!");
        var myClientId = $.connection.hub.id;
        setCookie("srconnectionid", myClientId);
    });

    function setCookie(cName, value, exdays) {
        var exdate = new Date();
        exdate.setDate(exdate.getDate() + exdays);
        var c_value = escape(value) + ((exdays == null) ? "" : "; expires=" + exdate.toUTCString());
        document.cookie = cName + "=" + c_value;
    }

my doubt is does it work in all signalr version? if not then how to handle it in new version specially for not generate a new connection id if page gets refreshed. looking for suggestion.

if we work with Persistent connection class instead of hub then what happen.....in this case connection id will persist if we refresh the page at client side? please guide. thanks

回答1:

SignalR allows you to send messages to a user via their IPrincipal.Identity.Name. Just use Clients.User(userName) instead of Clients.Client(connectionId).

If you for some reason cannot address a user using their IPrincipal.Identity.Name you could create your own IUserIdProvider. This is the replacement for IConnectionIdFactory which no longer exists in SignalR >= 1.0.0.

The equivalent IUserIdProvider would look like this:

public class MyConnectionFactory : IUserIdProvider
{
    public string GetUserId(IRequest request)
    {
        if (request.Cookies["srconnectionid"] != null)
        {
            return request.Cookies["srconnectionid"];
        }

        return Guid.NewGuid().ToString();
    }
}

public class Startup
{
    public void Configuration(IAppBuilder app)
    {
        var idProvider = new MyConnectionFactory();
        GlobalHost.DependencyResolver.Register(typeof(IUserIdProvider), () => idProvider);

        app.MapSignalR();
    }
}

public class MyHub : Hub
{
    public Task Send(string userName, string message)
    {
        return Clients.User(userName).receive(message);
    }
}

It would be really trivial to spoof a user given this MyConnectionFactory. You could make it more secure by using an HMAC.

Ideally you would just use the default IUserIdProvider which retrieves the user ID from IRequest.User.Identity.Name.



回答2:

The user id provider doesn't work, because the connection id doesn't come from it. I implemented a solution (https://weblogs.asp.net/ricardoperes/persisting-signalr-connections-across-page-reloads) that uses a pseudo-session id stored in session storage. Every SignalR connection id is then mapped to this pseudo-session id.