Как осуществить Аутенфикацию и Авторизацию пользователя на декстоп приложении для signalR?
Как реализовать авторизацию пользователя для декстоп приложения на signalR? Существует форма логина, которая состоит из пароля и логина. Нужно отправить логин и пароль и получить данные пользователя и авторизоваться на вебе signalR. Я не силен в вебе в принципе и пытаюсь найти информацию по этому поводу, но пока что слишком много вопросов. Хочется понять, как происходит сам процесс аутенфикации и авторизации с помощью токенов.
В кратце о ВЕБ проекте, есть хаб менеджер который контролирует пользователей при входы и выходе. Контекст с базой рабочий.
Декстоп пишу на WPF. В принципе это не важно.
Везде использую .NET 6.0
Прилагаю структуру SignalR решения:
ChatHub:
public class ChatHub : Hub<IChatHub>
{
public ChatHub(ChatHubManager hubManager) => _chatHubManager = hubManager;
private readonly ChatHubManager _chatHubManager;
private const string DefaultGroupName = "KPPGROUP";
#region Overrides
public override async Task OnConnectedAsync()
{
_chatHubManager.ConnectUser(Guid.NewGuid().ToString(), Context.ConnectionId);
await Groups.AddToGroupAsync(Context.ConnectionId, DefaultGroupName);
await UpdateUsersAsync();
await base.OnConnectedAsync();
}
public override async Task OnDisconnectedAsync(Exception? exception)
{
if(_chatHubManager.DisconnectUser(Context.ConnectionId)) await base.OnDisconnectedAsync(exception);
await Groups.RemoveFromGroupAsync(Context.ConnectionId, DefaultGroupName);
await UpdateUsersAsync();
await base.OnDisconnectedAsync(exception);
}
#endregion
[Authorize]
public async Task UpdateUsersAsync()
{
var users = _chatHubManager.ConnectedUsers.Select(x => x.Id).ToList();
await Clients.All.UpdateUsersAsync(users);
}
[Authorize]
public async Task SendPrivateMessageAsync(string senderId, string recipientId, byte[] message) =>
await Clients.All.SendPrivateMessageAsync(senderId, recipientId, message);
}
public interface IChatHub
{
public Task UpdateUsersAsync(IEnumerable<string> users);
public Task SendPrivateMessageAsync(string senderId, string recipientId, byte[] message);
}
UserConnection:
public class UserConnection
{
public UserConnection(string id)
{
Id = id;
_connections = new();
}
public string Id { get; set; }
public DateTime ConnectedAt
{
get
{
if (Connections.Any())
{
return Connections
.OrderByDescending(x => x.ConnectedAt)
.Select(x => x.ConnectedAt)
.First();
}
return new DateTime();
}
}
private readonly List<ChatConnection> _connections;
public IEnumerable<ChatConnection> Connections => _connections;
public void AppendConnection(string connectionId)
{
if (string.IsNullOrEmpty(connectionId)) throw new ArgumentNullException(nameof(connectionId));
_connections.Add(new()
{
ConnectionId = connectionId,
ConnectedAt = DateTime.Now,
});
}
public void RemoveConnection(string connectionId)
{
if (string.IsNullOrEmpty(connectionId)) throw new ArgumentNullException(nameof(connectionId));
var connection = _connections.FirstOrDefault(x => x.ConnectionId == connectionId);
if (connection == null) return;
_connections.Remove(connection);
}
}
ChatHubManager:
public class ChatHubManager
{
public List<UserConnection> ConnectedUsers { get; set; } = new();
public bool ConnectUser(string userId, string connectionId)
{
try
{
var existsUser = GetConnectedUserById(userId);
if (existsUser != null)
{
existsUser.AppendConnection(connectionId);
return true;
}
UserConnection user = new(userId);
user.AppendConnection(connectionId);
ConnectedUsers.Add(user);
return true;
}
catch (Exception ex) { return false; }
}
public bool DisconnectUser(string connectionId)
{
try
{
var user = GetConnectedUserByConnectionId(connectionId);
if (user == null) return true;
if (user.Connections.Count() == 1)
{
user.RemoveConnection(user.Connections.Last().ConnectionId);
ConnectedUsers.Remove(user);
return true;
}
if (!user.Connections.Any())
{
ConnectedUsers.Remove(user);
return true;
}
user.RemoveConnection(user.Connections.Last().ConnectionId);
return true;
}
catch(Exception ex)
{
return false;
}
}
private UserConnection? GetConnectedUserById(string userId) =>
ConnectedUsers.FirstOrDefault(x => x.Id == userId);
private UserConnection? GetConnectedUserByConnectionId(string connectionId) =>
ConnectedUsers.FirstOrDefault(x => x.Connections.Select(c => c.ConnectionId).Contains(connectionId));
}
ChatConnection:
public class ChatConnection
{
public DateTime ConnectedAt { get; set; }
public string ConnectionId { get; set; } = null!;
}
Program.cs:
using JurChat.Server.Hubs;
using JurChat.Server.Hubs.Infrastructure;
using JurChat.Server.Persistence;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddSignalR();
builder.Services.AddControllers();
builder.Services.AddDbContext<ApplicationDbContext>();
builder.Services.AddSingleton<ChatHubManager>();
var app = builder.Build();
app.UseDefaultFiles();
app.UseStaticFiles();
app.UseRouting();
app.MapHub<ChatHub>("/chat");
app.Run();
Источник: Stack Overflow на русском