Answered by:
Struggling to authenticate chat: Context.User.Identity.Name is null in SignalR Core hub

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
-
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
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.
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 worksAs 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