locked
Struggling to authenticate chat: Context.User.Identity.Name is null in SignalR Core hub RRS feed

  • Question

  • User-1142747527 posted

    I'm a little lost as how to implement authentication on SignalR. So the Javascript client is sending my ASP .Net Core 2.2 Web API an access/bearer token on the SignalR connection:

    this.hubConnection = new HubConnectionBuilder()
      .withUrl("http://mywebapi.com/chatHub", { accessTokenFactory: () => this.loginToken })
      .build();

    Now on the API side, I've got this on Startup.cs

     public void ConfigureServices(IServiceCollection services)
        {
            services.AddSignalR(hubOptions =>
            {
                hubOptions.EnableDetailedErrors = true;
                hubOptions.KeepAliveInterval = TimeSpan.FromSeconds(15);
            });
            services.AddSingleton<IUserIdProvider, NameUserIdProvider>();
    
            string domain = $"https://{Configuration["Auth0:Domain"]}/";
            services.AddAuthentication(options =>
            {
                options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
                options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
    
            }).AddJwtBearer(options =>
            {
                options.Authority = domain;
                options.Audience = Configuration["Auth0:ApiIdentifier"];
                options.RequireHttpsMetadata = false;
                options.Events = new JwtBearerEvents
                {
                    OnMessageReceived = chatContext =>
                    {
                        var accessToken = chatContext.Request.Query["access_token"];
    
                        // If the request is for our hub...
                        var httpContextRequestPath = chatContext.HttpContext.Request.Path;
                        if (!string.IsNullOrEmpty(accessToken) &&
                            (httpContextRequestPath.StartsWithSegments("/hubs/chat")))
                        {
                            // Read the token out of the query string
                            chatContext.Token = accessToken;
                        }
                        return Task.CompletedTask;
                    }
                };
            });
        }
    
        public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerManager logger)
        {
            app.UseSignalR(routes =>
            {
                routes.MapHub<ChatHub>("/chatHub");
           });
        }

    Then I have this class:

    public class NameUserIdProvider : IUserIdProvider
    {
        public string GetUserId(HubConnectionContext connection)
        {
            return connection.User?.Identity?.Name;
        }
    }

    And finally, on my SignalR Core hub I have:

    [Authorize]
    public class ChatHub : Hub { private readonly static ConnectionMapping<string> _connections = new ConnectionMapping<string>(); public override async Task OnConnectedAsync() { string name = Context.User.Identity.Name; _connections.Add(name, Context.ConnectionId); await Clients.All.SendAsync("UserConnected", Context.ConnectionId); await base.OnConnectedAsync(); } }

    However, Context.User.Identity.Name is null. In fact, most of the properties of Context.User.Identity are null. What am I doing wrong? Thanks...

    Monday, July 1, 2019 1:04 PM

Answers

All replies

  • User475983607 posted

    Have you gone through the reference documentation?
    https://docs.microsoft.com/en-us/aspnet/core/signalr/authn-and-authz?view=aspnetcore-2.2

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Monday, July 1, 2019 1:08 PM
  • User-1142747527 posted

    Ok, I see I forgot this line:

    services.AddSingleton<IUserIdProvider, NameUserIdProvider>();

    And this:

    public class NameUserIdProvider : IUserIdProvider
    {
        public string GetUserId(HubConnectionContext connection)
        {
            return connection.User?.Identity?.Name;
        }
    }

    I will edit my original question to show this. But even after adding this, it's still nor working? Everything else, as far as I can see, seems to be ok?

    Monday, July 1, 2019 1:17 PM
  • User475983607 posted

    You are also musing [Authorize] attributes.  Please go through the linked documentation and double check your work.

    https://docs.microsoft.com/en-us/aspnet/core/signalr/authn-and-authz?view=aspnetcore-2.2#authorize-users-to-access-hubs-and-hub-methods

    Monday, July 1, 2019 1:23 PM
  • User-1142747527 posted

    Oh yes, indeed. Thanks for that. I've added it (and updated my original question correspondingly) and still not working. But I will now compare the two in detail and see if I've missed anything else. Thanks

    Monday, July 1, 2019 1:48 PM
  • User-1142747527 posted

    Ok seems to be working now, sort of.  Context.User.Identity.Name is still null. But Context.User.FindFirst(ClaimTypes.NameIdentifier).Value works.

    Thanks again for all your help!

    Tuesday, July 2, 2019 6:46 AM
  • User283571144 posted

    Hi f.a.rodriguez,

    Ok seems to be working now, sort of.  Context.User.Identity.Name is still null. But Context.User.FindFirst(ClaimTypes.NameIdentifier).Value works

    As far as I know, the rason about  Context.User.Identity.Name is null is the JwtSecurityToken's claim doesn't contains the ClaimTypes.Name value.

    If you want to add it , you should modify your claims to genreate the claims token.

    More details, you could refer to below codes:

    Notice:Since I don't know your generate token method, I juest add my codes:

            public string GetToken() {
      
    
                var claims = new[] {
                      new Claim(JwtRegisteredClaimNames.NameId,"name1"),
                      new Claim(JwtRegisteredClaimNames.Sub,"name1"),
                      new Claim("customer","customer1"),
                      new Claim(JwtRegisteredClaimNames.Email,"wuxiyuan@sina,com"),
                      new Claim("role","user"),
                      new Claim(ClaimTypes.Name, "Brando")
                };
                var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("myStringsadasdasdasdsadadasdasdsdadasdd"));
                var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
                var token = new JwtSecurityToken("name1",
                 "name1",
                claims,
                expires: DateTime.Now.AddDays(1),
                signingCredentials: creds);
    
                return new JwtSecurityTokenHandler().WriteToken(token);
            }

    Result:

    Best Regards,

    Brando

    Tuesday, July 2, 2019 8:08 AM
  • User-1142747527 posted

    Thanks Brando. I will try that out

    Thursday, July 4, 2019 7:04 AM