Aspnetcore: Why I can't get current logged in user in asp.net core SignalR?

Created on 2 Jan 2019  路  4Comments  路  Source: dotnet/aspnetcore

I'm working on a chat project by asp.net core 2.2 signalR project. I implemented asp.net core identity a project I can authenticate persons without any problem this is a scenario of my project. A user enters username and password, and my login controller checks it if everything is ok after that I generate a JwtToken and return Ok result to Login Razor page the login page redirects me to chat section and so far everything works correctly but when I want to get a current user in my chat hub it failed and I got NullRefrenceException.
signalrfailded

public class ChatHub : Hub
    {
        public HubConnectionContext hubConnection;
        public async Task SendMessage(string name, string text)
        {
            var personPricture = "https://devilsworkshop.org/files/2013/01/enlarged-facebook-profile-picture.jpg";
            var message = new ChatMessage
            {
                SenderName = name,
                Text = text,
                SendAt = DateTimeOffset.Now
            };
            await Clients.All.SendAsync("ReciveMessage",
            message.SenderName,
            message.SendAt, message.Text, personPricture);

        }

        public Task SendMessageToUser(string connectionId, string message)
        {

            return Clients.Client(connectionId).SendAsync("ReceiveMethod", message);
        }

        private readonly HashSet<string> onlineUsers = new HashSet<string>();
        public override async Task OnConnectedAsync()
        {
            **if (Context.User.Identity.IsAuthenticated)**
            {
                var name = Context.User.Identity.Name;
            }

            onlineUsers.Add(Context.ConnectionId);
            await Clients.Caller.SendAsync("UserConnected", Context.ConnectionId);
            await base.OnConnectedAsync();
        }

        public override async Task OnDisconnectedAsync(Exception ex)
        {
            onlineUsers.Remove(Context.ConnectionId);
            await Clients.All.SendAsync("UserDisconnected", Context.ConnectionId);
            await base.OnDisconnectedAsync(ex);
        }
    }
  [HttpPost, Route("Login")]
        public async Task<IActionResult> Login([FromBody]LoginViewModel user)
        {
            object tokenString;
            if (user == null)
            {
                return BadRequest("Invalid client request");
            }
            var findUser = await _userManager.FindByNameAsync(user.UserName);
            if (findUser == null)
            {
                return NotFound();
            }
            else if (findUser != null)
            {
                var result = await _signManager.
                    PasswordSignInAsync(user.UserName,
                    user.Password,
                    false, lockoutOnFailure: false);
                if (!result.Succeeded)
                    return BadRequest();
                else
                {
                    tokenString = await GenerateJwtToken(findUser.Email, findUser);
                    return Ok(new {token = tokenString});
                    //return Redirect("/");
                }

            }
            else
            {
                return Unauthorized();
            }

        }

       public async Task<string> GenerateJwtToken(string email, AppUser user)
        {

            var claims = new List<Claim>{
                new Claim(JwtRegisteredClaimNames.Sub,email),
                new Claim(JwtRegisteredClaimNames.Jti,Guid.NewGuid().ToString()),
                new Claim(ClaimTypes.NameIdentifier,user.Id)
            };

            var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("ThisIsMyPasswrod3"));
            var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
            var expires = DateTime.Now.AddDays(Convert.ToDouble(30));

            var token = new JwtSecurityToken(
                issuer: "http://localhost:8916",
                audience: "http://localhost:8916",
                claims: claims,
                expires: expires,
                signingCredentials: creds
            );
            return new JwtSecurityTokenHandler().WriteToken(token);
        }
  $(document).ready(function () {
            $('#login').click(function () {
                let UserName = $('#username').val();
                let Password = $('#password').val();
                let user = { UserName: UserName, Password: Password };
                console.log($('#password').val());
                $.ajax({
                    url: '/api/auth/Login',
                    type: 'post',
                    contentType: 'application/json',
                    data: JSON.stringify(user),
                    success: function (data) {
                        let token = data.token;
                        console.log(token);
                        url = "/?jwt=" + token;
                        window.location.href = url;
                    },
                    error: function (data) {
                        console.log(data);
                    }
                })

            });
        });

```
public void ConfigureServices(IServiceCollection services)
{

        services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
        services.AddSignalR(config => { config.EnableDetailedErrors = true; });
        services.AddDbContext<ApplicationDbContext>
        (options => options.UseSqlServer("Data Source=(local);Integrated Security=True;Initial Catalog=ChatDB;"));
        services.AddIdentity<AppUser, AppRole>()
            .AddEntityFrameworkStores<ApplicationDbContext>().AddDefaultTokenProviders();
        services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
        .AddJwtBearer(options => options.TokenValidationParameters =
            new TokenValidationParameters
            {
                ValidateLifetime = true,
                ValidateIssuer = true,
                ValidateAudience = true,
                ValidateIssuerSigningKey = true,
                ValidIssuer = "http://localhost:8916",
                ValidAudience = "http://localhost:8916",
                IssuerSigningKey = new SymmetricSecurityKey(
                    Encoding.UTF8.GetBytes(Configuration["SecurityKey"]))
            });


        services.Configure<IdentityOptions>(op =>
        {
            op.Password.RequireDigit = false;
            op.Password.RequiredLength = 3;
            op.Password.RequireLowercase = false;
            op.Password.RequireNonAlphanumeric = false;
            op.Password.RequireUppercase = false;
        });
    }

    // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }


        app.UseSignalR(op => { op.MapHub<ChatHub>("/chatter"); });
        app.UseAuthentication();

        app.UseMvc();
        app.UseStaticFiles();
    }

```

area-signalr

Most helpful comment

Also, you should consider putting the [Authorize] attribute on your Hub so every invocation runs the auth check.

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

All 4 comments

What does your SignalR client code look like? Are you passing the jwt token through via the accessTokenFactory? See https://docs.microsoft.com/en-us/aspnet/core/signalr/authn-and-authz?view=aspnetcore-2.2#bearer-token-authentication for some info on using JWT with SignalR.

Also, you should consider putting the [Authorize] attribute on your Hub so every invocation runs the auth check.

Also, you should consider putting the [Authorize] attribute on your Hub so every invocation runs the auth check.

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

Thanks a lot. But, I want to say my problem was two things. One of them was [Authorize] and another was about order of middlewares: I changed order of middlewares
From

app.UseSignalR(op => { op.MapHub<ChatHub>("/chatter"); });
app.UseAuthentication();

to

app.UseAuthentication();
app.UseSignalR(op => { op.MapHub<ChatHub>("/chatter"); });

Was this page helpful?
0 / 5 - 0 ratings