The goal is to use a Blazor server as a relay server using signalR. I have little to no experience with blazor servers before this. The Idea would be to connect a Winform/Xamarin client to this server, target the recipient using a name/id from an existing database, and relay the necessary info.
Hub:
[Authorize]
public class ChatHub : Hub
{
public Task SendMessageAsync(string user, string message)
{
//Context.UserIdentifier
Debug.WriteLine(Context.UserIdentifier);
Debug.WriteLine(Context?.User?.Claims.FirstOrDefault());
return Clients.All.SendAsync("ReceiveMessage", user, message); ;
}
public Task DirectMessage(string user, string message)
{
return Clients.User(user).SendAsync("ReceiveMessage", user, message);
}
}
As per documentation I'm trying to set the Context.UserIdentifier, I do however struggle with the authentication part. My program.cs looks like this:
var builder = WebApplication.CreateBuilder(args);
var services = builder.Services;
services.AddTransient<IUserIdProvider, MyUserIdProvider>();
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
}).AddJwtBearer(options =>
{
options.Events = new JwtBearerEvents
{
OnMessageReceived = context =>
{
//var accessToken = context.Request.Query["access_token"];
var accessToken = context.Request.Headers["Authorization"];
var path = context.HttpContext.Request.Path;
if (!string.IsNullOrEmpty(accessToken) && path.StartsWithSegments("/chathub"))
{
context.Token = accessToken;
}
return Task.CompletedTask;
}
};
});
services.AddRazorPages();
services.AddServerSideBlazor();
services.AddSignalR();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseAuthentication();
app.UseRouting();
app.UseAuthorization();
app.MapBlazorHub();
app.MapHub<ChatHub>("/chathub");
app.MapFallbackToPage("/_Host");
app.Run();
As for my Client (a winform test client) I tried something like this:
HubConnection chatHubConnection;
chatHubConnection = new HubConnectionBuilder()
.WithUrl("https://localhost:7109/chathub", options =>
{
options.AccessTokenProvider = () => Task.FromResult(token);
})
.WithAutomaticReconnect()
.Build();
private async void HubConBtn_Click(object sender, EventArgs e)
{
chatHubConnection.On<string, string>("ReceiveMessage", (user, message) =>
{
this.Invoke(() =>
{
var newMessage = $"{user}: {message}";
MessagesLB.Items.Add(newMessage);
});
});
try
{
await chatHubConnection.StartAsync();
MessagesLB.Items.Add("Connected!");
HubConBtn.Enabled = false;
SendMessageBtn.Enabled = true;
}
catch (Exception ex)
{
MessagesLB.Items.Add(ex.Message);
}
}
As a first step I'm just trying to authenticate a user/check that it's in the live database, if so connect and fill out: Context.UserIdentifier so I can use this within the Hub. I understand that I probably need a middleware however I don't really know exactly how to test a connectionId/Jwt token or similar to get the user/connection.
Any nudge in the right direction would be appreciated.