0
votes

I created two projects from templates.

The first contains Membership and MVC4. And the second uses MVC5 and Asp.Net Identity.

Then I added signalR to both projects using same code.

In Membership project I can access HttpContext.User both in controllers and SignalR connection class(OnConnected method). But in Identity project I have proper value of HttpContext.User only in controllers. In OnConnected method HttpContext.User returns null.

Code of signalR is same in both projects:

1) SynchronizationConnection.cs

public class SynchronizationConnection : PersistentConnection
{
    public SynchronizationConnection()
    { 
    }
    protected override Task OnReceived(IRequest request, string connectionId, string data)
    {
        Debugger.Break();
        return base.OnReceived(request, connectionId, data);
    }

    protected override Task OnConnected(IRequest request, string connectionId)
    {
        Debugger.Break(); //HttpContext.Current.User == null
        return base.OnConnected(request, connectionId);
    }

    protected override Task OnDisconnected(IRequest request, string connectionId)
    {
        Debugger.Break();
        return base.OnDisconnected(request, connectionId);
    }
}

2) Startup.cs

public partial class Startup
{
    public void Configuration(IAppBuilder app)
    {
        app.MapSignalR();
        ConfigureAuth(app);
    }
}

3) Startup.Auth.cs

public partial class Startup
{

    public void ConfigureAuth(IAppBuilder app)
    {
        app.MapSignalR<Services.Realtime.SynchronizationConnection>("/test");
        app.UseCookieAuthentication(new CookieAuthenticationOptions
        {
            AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
            LoginPath = new PathString("/Account/Login")
        });

        app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);
    }
}

4) Client javascript

var connection = $.connection('/test');
connection.logging = true;
console.log('Receiving connection');
connection.received(function (data) {
    console.log('received');  
});

connection.disconnected(function () {
    console.log('disconnected');
});

connection.error(function (data) {
    console.log('error');
});

connection.start().done(function () {
    console.log('Connection started');
});

I've seen questions about null User.Identity.Name because of missing [Authorize] attribute. In my case I cannot access even User.Identity. Also I have [Authorize] attribute on my action, that contains client javascript.

2
How did you resolved it?Mr. Robot

2 Answers

0
votes

Inside of the OnConnected method, you can use:

request.User

That will carry the IPrincipal that was in the HttpContext.Current.User at the time of connection, and it is the one you should mind.

If you need to alter that IPrincipal (like removing the default one generated by Forms authentication and set your own), I recommend you to use an IHttpModule. All the transports in SignalR at least start as an HTTP (even WebSockets), so all transports are going to hit the module at least during connection.

Cheers.

0
votes

I had the same problem: request.User was null in the PersistentConnection's OnConnected() method. Changing the order in which I initialized SignalR and my authentication provider fixed it. I changed it so that my SignalR endpoints were mapped after my authentication was configured:

app.UseCookieAuthentication(new CookieAuthenticationOptions
{
    AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
    LoginPath = new PathString("/Account/Login"),
    ExpireTimeSpan = new TimeSpan(999, 0, 0, 0),
    SlidingExpiration = true
});

GlobalConfiguration.Configuration.UseSqlServerStorage("MyDatabase", new SqlServerStorageOptions() { PrepareSchemaIfNecessary = false });

app.MapSignalR<MyConnection>("/MyConnection");