PERMITIR SOMENTE 1 LOGIN

NOWLIGHTS 06/10/2022 20:28:39
#500567
Boa noite!

Pessoal, de forma bem resumida e simples, como faço para que o sistema em Asp.Net Core MVC com .net 6.0 permita somente 1 login por vez por usuário (logins concorrentes se não me engano), ex.: se o usuário João está logado, e outra pessoa logue na conta dele, então ele é desconectado, é possivel?

O que uso para realizar o login:

   ClaimsPrincipal pr = new ClaimsPrincipal(identity);
await HttpContext.SignInAsync("x", pr);
MRSILVA 09/10/2022 19:57:47
#500571
Resposta escolhida
Olá.
Quando eu precisei disso não encontrei uma solução pronta até fiz uma pergunta aqui sobre isso.

Criei meu próprio verificador da seguinte forma:

Criei uma classe Singleton que controla os login dos usuarios, toda vez que usuário faz login ou qualquer requisição passa por essa classe, crio um identificador do login, se fazer o login em duas maquinas o primeiro login e excluido, dessa forma não é possível mais concluir nenhuma requisição do primeiro login.
Esse controle é tudo feito no servidor não tem nenhuma interferencia do front-end

Para isso voce tem que identificar as requisições no servidor por usuário, fiz isso adaptando isso

Eu injeto essa classe Singleton em todas as requisições criando um serviço na classe startup
services.AddSingleton<UsuarioLogadoSingleton>();

Está funcionando bem para mim, na época que fiz não encontrei nada pronto, conseguir personalizar todas as regras de acesso de numero de usuários logados por empresa entre outras verificações.
NOWLIGHTS 12/12/2022 18:07:29
#500868
Então,

usei uma abordagem quase igual;

Criei uma classe somente para gerenciar os logins.
Todo login realizado, eu gero um Guid como referencia do login e salvo tanto no Identity quanto na memoria, com isso, tenho uma alta velocidade de resposta (sistema possui acesso somente para 50 usuários, podem aumentar até no maximo 400, então acredito que não pesaria muito a memoria para realizar isso)

  public class GuidSessions
{
public GuidSessions(int idUsuario, string guid)
{
IdUsuario = idUsuario;
Guid = guid;
}

public int IdUsuario { get; set; }
public string Guid { get; set; }
}

public bool isExpire(int IdUsuario, string GuidSession)
{
var dataCache = GetCacheJson();
dataCache.ForEach(x => Console.WriteLine(x.IdUsuario + " - " + x.Guid + ""));
Console.WriteLine("--------------");
var itemsCache = dataCache.Where(x => x.IdUsuario == IdUsuario);
if (itemsCache.Any())
{
if (itemsCache.LastOrDefault() != null && itemsCache.LastOrDefault().Guid != GuidSession)
return true;
return false;
}
return true;
}


private void SaveCacheJson(List<GuidSessions> data)
{
memoryCache.Set(Key, JsonSerializer.Serialize(data));
}
private List<GuidSessions> GetCacheJson()
{
memoryCache.TryGetValue(Key, out string dataInCache);
if (!string.IsNullOrWhiteSpace(dataInCache))
return JsonSerializer.Deserialize<List<GuidSessions>>(dataInCache);
return new();
}

public void InsertCacheJson(GuidSessions data)
{
var itemsCache = GetCacheJson();
itemsCache.RemoveAll(x => x.IdUsuario == data.IdUsuario);
itemsCache.Add(data);
SaveCacheJson(itemsCache);
}


E no startup, criei um middleware para acessar esses dados em todas as requisições,

  public async Task InvokeAsync(HttpContext context)
{
if (context.User.Identity.IsAuthenticated)
{
if (_userAuthentic.isExpire(context.User.Identity.GetId(), context.User.Identity.GetGuidSession()))
context.Response.Redirect("/logout");
}
await _next(context);
}


Postei aqui pois queria uma opnião dos mais experientes, se terei algum problema em realizar dessa forma.
MRSILVA 13/12/2022 16:17:46
#500870
Olá.
Que bom que deu certo.

Meu controle também é praticamente tudo na memória não tem limitação de usuários. Não sei para que serve sua solução mas acho muito limitado 400 usuários, acho que não precisa se preocupar muito com a memória ao não ser que esteja guardando muito dados do usuário para não usar o banco de dados (O que voce está guardando de cada usuário?).
Mas legal, tomara que pessoal mais experiente responda.
Tópico encerrado , respostas não são mais permitidas