// Método usado para enviar um pedido para o servidor GRPC com o intuito de autenticar um utilizador private void LoginView_LoginRequest(string username, string password) { // Se o client estiver a null, significa que ocorreu algum erro, e é finalizada a conexão if (AuthClient == null) { Program.ConnectController.ConnectionError(); return; } // Tenta autenticar o utilizador try { // Modelo com as informações do pedido para o servidor tratar. UserLoginLookupModel logReq = new UserLoginLookupModel { Username = username, Password = password }; // Comunicação de forma sincrona com o servidor. Esta comunicação foi feita de forma sincrona devido ao facto de, de alguma forma, o método login ser chamado duas vezes. Este facto levava a inconsistência no serviço de créditos, uma vez que cada vez que é executada uma ação de login, o id de sessão é atualizado. Se este método forsse chamado de forma asincrona, muitas das vezes não seria possível comunicar com o servidor de créditos porque poderia acontecer o caso em que o servidor de jogo tinham um id de sessão e o servido de créditos outro. UserLoginModel outcome = AuthClient.Login(logReq); // No caso de autenticação falhar, é enviada a mensagem de erro ao utilizador if (outcome.Valid == false) { Program.LoginView.ShowError("User or/and password do not match any user!"); return; } // Se a autenticação for feita com sucesso, é guardado o ID de sessão do Username do utilizador no client Program.SetAuthenticatedUser(outcome.SessionID, username); } // No caso de a conexão com o servidor falhar, é chamado o método de ConnectController para finalizar todas as conexões catch (Grpc.Core.RpcException) { Program.ConnectController.ConnectionError(); return; } catch (JsonException jsonEx) { Program.CreditBankMenurView.ShowMessageBox("Unable to login in the API due to json parse exception:\n" + jsonEx + "\nAuthController: LoginView_LoginRequest"); return; } catch (ArgumentNullException nullEx) { Program.CreditBankMenurView.ShowMessageBox("Unable to login in the API due to null exception:\n" + nullEx + "\nAuthController: LoginView_LoginRequest"); return; } catch (HttpRequestException httpEx) { Program.CreditBankMenurView.ShowMessageBox("Unable to login in the API due to Http request exception:\n" + httpEx + "\nAuthController: LoginView_LoginRequest"); return; } // O utilizador é avisado que a autenticação foi feita com sucesso Program.LoginView.SuccessfulLogin(); }
/** * Login de utilizadores já existentes. Devem ser recebidos o username e password. * Sempre que o login é feito com sucesso, é enviado um ID de sessão único para o cliente * que é usado por este para se identificar sempre que envia algum pedido. */ public async override Task <UserLoginModel> Login(UserLoginLookupModel request, ServerCallContext context) { UserLoginModel output = new UserLoginModel(); // Transformação de todos os carateres do nome para upper case string username = request.Username;//.ToUpper(); // Encriptação da password SHA512 sha512 = SHA512Managed.Create(); byte[] bytes = sha512.ComputeHash(Encoding.UTF8.GetBytes(request.Password)); string password = Convert.ToBase64String(bytes); // Verifica-se se o utilizador existe na base de dados e se a password está correta Models.User u = _context.User.FirstOrDefault(u => u.Username == request.Username && u.Password == password); if (u == null) { // Se não existir nenhuma entrada na base de dados com o username e password igual, então o output tem de ser autenticação inválida. output.Valid = false; output.SessionID = ""; } else { // Sempre que um utilizador se autentica, é gerado sempre um novo ID de sessão. // É usado um ciclo para, no caso do ID de sessão gerado já existir, poder gerar um novo bool success; do { success = true; try { u.GenerateSessionID(); _context.SaveChanges(); // Altera o id de sessão do cliente, na base de dados da API. await APIServerCommunication.UserLogin(u.SessionID, u.Id); } // Exceção que é lançada sempre que é quebrado o constraint UNIQUE do ID de sessão, no caso do ID de sessão gerado já existir catch (DbUpdateException e) when(e.InnerException is SqlException sqlEx && (sqlEx.Number == 2627 || sqlEx.Number == 2601)) { success = false; } }while (success == false); // Se o login for feito com sucesso, é enviada uma confirmação ao cliente, com o seu ID de sessão output.Valid = true; output.SessionID = u.SessionID; } return(await Task.FromResult(output)); }
static async Task Main(string[] args) { Boolean valido1 = false; String loginOuRegisto = ""; int userDBId = -1; while (!valido1) { Console.WriteLine("Antes de continuar, já tem conta ou não (Y/N)?\n"); loginOuRegisto = Console.ReadLine(); loginOuRegisto.ToUpper(); if ((loginOuRegisto.Equals("N") || loginOuRegisto.Equals("Y"))) { valido1 = true; } } String username, password, email, confirmacaoPassword; Boolean valido = false; loginOuRegisto.ToUpper(); while (!valido) { if (loginOuRegisto.Equals("Y")) { Console.WriteLine("\nUsername: "******"\nPassword: "******"https://localhost:5001"); var client = new User.UserClient(channel); var reply = await client.LoginAsync(clientRequest); valido = reply.Valid; // Caso a autenticação seja bem sucedida, o valor retornado é true. Quando o valor da variavel "valido" é true, a execução já não entrará novamente no ciclo while, passando para a nova fase. if (valido) { Console.WriteLine("\nEstás autenticado! "); userDBId = reply.UserId; } else { Console.WriteLine("\nNão estás autenticado! "); } } else if (loginOuRegisto.Equals("N")) { Console.WriteLine("\nUsername: "******"\nEmail: "); email = Console.ReadLine(); Console.WriteLine("\nPassword: "******"\nConfirmação da password: "******"\nO campo Pasword e o de confirmação de password não são iguais. Tente novamente."); continue; } // Verificar a existência destes valores na base de dados do servidor e registar o utilizador. var clientRequest = new UserRegistLookupModel { Username = username, Email = email, Password = password }; var channel = GrpcChannel.ForAddress("https://localhost:5001"); var client = new User.UserClient(channel); var reply = await client.RegistAsync(clientRequest); valido = reply.Valid; // Caso o registo seja bem sucedida, o valor retornado é true. Quando o valor da variavel "valido" é true, a execução já não entrará novamente no ciclo while, passando para a nova fase. if (!valido) { Console.WriteLine("\nErro no registo! "); } else { valido = false; loginOuRegisto = "Y"; // Vai continuar no ciclo, mas desta vez para fazer a autenticação. } } } Console.WriteLine("Agora que está autenticado, vamos jogar!\n"); Console.WriteLine("Comandos possíveis:\n"); Console.WriteLine("\t -> play pedra: Jogada pedra;\n"); Console.WriteLine("\t -> play tesoura: jogada tesoura;\n"); Console.WriteLine("\t -> play papel: Jogada papel;\n"); Console.WriteLine("\t -> stats: Ver as suas estatísticas;\n"); Console.WriteLine("\t -> end: Finalizar o jogo;\n"); Console.WriteLine("\t -> help: Ver esta tabela novamente;\n"); bool validoJogo = true; while (validoJogo) { string input = Console.ReadLine(); var channel = GrpcChannel.ForAddress("https://localhost:5001"); var client = new Game.GameClient(channel); if (input.Equals("play pedra")) { var clientRequest = new PlayLookupModel { UserId = userDBId, Play = 1 }; var reply = await client.PlayAsync(clientRequest); if (reply.Result == 1) { Console.WriteLine("Resumo do jogo:\n\tCliente: Pedra\n\tServidor: " + reply.ServerPlay + "\n\tResultado final: O cliente ganhou!\n\n"); } else if (reply.Result == 2) { Console.WriteLine("Resumo do jogo:\n\tCliente: Pedra\n\tServidor: " + reply.ServerPlay + "\n\tResultado final: O servidor ganhou!\n\n"); } else if (reply.Result == 0) { Console.WriteLine("Resumo do jogo:\n\tCliente: Pedra\n\tServidor: " + reply.ServerPlay + "\n\tResultado final: Empate!\n\n"); } } else if (input.Equals("play papel")) { var clientRequest = new PlayLookupModel { UserId = userDBId, Play = 2 }; var reply = await client.PlayAsync(clientRequest); if (reply.Result == 1) { Console.WriteLine("Resumo do jogo:\n\tCliente: Pedra\n\tServidor: " + reply.ServerPlay + "\n\tResultado final: O cliente ganhou!\n\n"); } else if (reply.Result == 2) { Console.WriteLine("Resumo do jogo:\n\tCliente: Pedra\n\tServidor: " + reply.ServerPlay + "\n\tResultado final: O servidor ganhou!\n\n"); } else if (reply.Result == 0) { Console.WriteLine("Resumo do jogo:\n\tCliente: Pedra\n\tServidor: " + reply.ServerPlay + "\n\tResultado final: Empate!\n\n"); } } else if (input.Equals("play tesoura")) { var clientRequest = new PlayLookupModel { UserId = userDBId, Play = 3 }; var reply = await client.PlayAsync(clientRequest); if (reply.Result == 1) { Console.WriteLine("Resumo do jogo:\n\tCliente: Pedra\n\tServidor: " + reply.ServerPlay + "\n\tResultado final: O cliente ganhou!\n\n"); } else if (reply.Result == 2) { Console.WriteLine("Resumo do jogo:\n\tCliente: Pedra\n\tServidor: " + reply.ServerPlay + "\n\tResultado final: O servidor ganhou!\n\n"); } else if (reply.Result == 0) { Console.WriteLine("Resumo do jogo:\n\tCliente: Pedra\n\tServidor: " + reply.ServerPlay + "\n\tResultado final: Empate!\n\n"); } } else if (input.Equals("stats")) { if (userDBId != -1) { var clientRequest = new StatsLookupModel { UserId = userDBId }; var reply = await client.StatsAsync(clientRequest); Console.WriteLine("\nAs suas estatísticas:\n\t-> Jogos feitos: " + reply.GamesPlayed.ToString() + "\n\t->Ganhos: " + reply.Wins.ToString() + "\n\t->Perdidos: " + reply.Losts.ToString() + "\n\t->Empatados: " + reply.Draws.ToString() + "\n\n"); } } else if (input.Equals("end")) { // TODO: Fechar conexão com o gRPC validoJogo = false; } else if (input.Equals("help")) { Console.WriteLine("Comandos possíveis:\n"); Console.WriteLine("\t -> play rock: Jogada pedra;\n"); Console.WriteLine("\t -> play scissors: jogada tesoura;\n"); Console.WriteLine("\t -> play paper: Jogada papel;\n"); Console.WriteLine("\t -> stats: Ver as suas estatísicas;\n"); Console.WriteLine("\t -> end: Finalizar o jogo;\n"); Console.WriteLine("\t -> help: Ver esta tabela novamente;\n"); } else { Console.WriteLine("Comando inválido"); } } }