I have a simple chat implementation in SignalR. Everyone may read what others are typing, but only registered users may speak:
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.SignalR;
using System.Threading.Tasks;
namespace WebApplication1.Hubs
{
public class ChatHub : Hub
{
[Authorize]
public async Task SendMessage(string message)
{
await Clients.All.SendAsync("ReceiveMessage", Context.User.Identity.Name, message);
}
}
}
And it works. Except... When the user has the chat opened in one tab, but logs in / logs out in the other tab.
Why, in spite of the presence of the [Authorize]
attribute, does the SendMessage
method still work even if the user is no longer authenticated?
How to fix this? How to make my chat hub follow authentications that happen after the client has connected?
ASP .NET Core 2.1 RC1, because 2.0 doesn't support SignalR.
EDIT: As per request from comments, Startup.Configure
:
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseDatabaseErrorPage();
}
else
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseCookiePolicy();
app.UseAuthentication();
app.UseSignalR(routes =>
{
routes.MapHub<ChatHub>("/chathub");
});
app.UseMvc();
}
In websocket credentials are only sent to establish the connexion and are not included in every frame. So once the connexion established there's no way for signalr to know that the user has logged off.
Like you said when the user logs off you could open another socket to send a message to all tabs that the user has logged off.
Or you could periodicaly check the cookies by javascript that to check the user is still log in and close the signalr connexion if he is not.
Another solution would be to use Shared Worker or Broadcast channel to send message between tabs.