primeros cambios para manejar los permisos y grupos

This commit is contained in:
2024-11-02 15:41:15 -03:00
parent e550952397
commit 735cdfc344
16 changed files with 249 additions and 86 deletions
+9 -5
View File
@@ -1,3 +1,4 @@
using Entidades.Dto;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Modelo; using Modelo;
@@ -7,14 +8,17 @@ namespace AlquilaFacil.Controllers;
public class AccionesController: ControllerBase { public class AccionesController: ControllerBase {
[HttpPost("api/acciones")] [HttpPost("api/acciones")]
public IActionResult ListarAccionesPorUsuario([FromBody] string email) { public IActionResult ListarAccionesPorUsuario([FromBody] LoginDto email, [FromHeader(Name = "Auth")] string Auth) {
Request.Cookies.TryGetValue("token", out var token); if (email.Email == "" || email.Email == null) return BadRequest();
if (token == null) return Unauthorized(new { esValido = false});
bool esValido = RepositorioUsuarios.Singleton.CheckToken(email, token);
if (Auth == "") return Unauthorized(new { esValido = false});
bool esValido = RepositorioUsuarios.Singleton.CheckToken(email.Email, Auth);
if (!esValido) return Unauthorized(); if (!esValido) return Unauthorized();
var Permisos = RepositorioPermisos.Singleton.ListarPermisos(email); var Permisos = RepositorioPermisos.Singleton.ListarPermisos(email.Email);
Response.Headers["Content-Type"] = "application/json";
return Ok(Permisos); return Ok(Permisos);
} }
} }
+18
View File
@@ -0,0 +1,18 @@
#if DEBUG
using Microsoft.AspNetCore.Mvc;
using Modelo;
namespace AlquilaFacil.Controllers;
[ApiController]
public class GruposController: ControllerBase {
[HttpPost("api/admin/grupos")]
public IActionResult CrearPermisos([FromBody] AdminGrupo grupo) {
if (String.IsNullOrEmpty(grupo.descripcion)) return BadRequest();
bool ret = RepositorioGrupos.Singleton.CrearGrupo(grupo.descripcion);
return (ret) ? Ok(ret) : BadRequest();
}
}
public record AdminGrupo(string descripcion);
#endif
+10 -2
View File
@@ -12,8 +12,16 @@ public class InquilinoController: ControllerBase
{ {
[HttpGet("api/inquilino")] [HttpGet("api/inquilino")]
public IActionResult Get() { public IActionResult Get([FromHeader(Name = "Auth")] string Auth) {
return Ok(); if (!string.IsNullOrEmpty(Auth)) return BadRequest();
string path = Request.Path;
var ret = RepositorioPermisos.Singleton.CheckPermisos(Auth, path);
if (ret == false) return BadRequest(ret);
var list = RepositorioInquilinos.Singleton.GetInquilinos();
return Ok(list);
} }
[HttpPost("api/inquilino")] [HttpPost("api/inquilino")]
+12 -7
View File
@@ -25,18 +25,18 @@ public class LoginController: ControllerBase
{ {
HttpOnly = true, HttpOnly = true,
Secure = true, Secure = true,
//SameSite = SameSiteMode.Strict, SameSite = SameSiteMode.None,
Path = "/Menu",
Expires = DateTimeOffset.UtcNow.AddHours(1) Expires = DateTimeOffset.UtcNow.AddHours(1)
}; };
Response.Cookies.Append("token", tokenString, cookieOptions); Response.Cookies.Append("token", tokenString, cookieOptions);
return Ok( new {Email = loginDto.Email, Redirect = "/Menu"}); return Ok( new {Email = loginDto.Email, Token = tokenString, Redirect = "/Menu"});
} }
[HttpPost("api/login/validar")] [HttpPost("api/login/validar")]
public IActionResult Verificar([FromBody] AccessDto request){ public IActionResult Verificar([FromBody] AccessDto request, [FromHeader(Name = "Auth")] string token){
Request.Cookies.TryGetValue("token", out var token);
if (request.Email == String.Empty || token == null ||request.Redirect == string.Empty) if (request.Email == String.Empty || token == null ||request.Redirect == string.Empty)
{ {
@@ -44,8 +44,13 @@ public class LoginController: ControllerBase
} }
bool esValido = RepositorioUsuarios.Singleton.CheckToken(request.Email, token); bool esValido = RepositorioUsuarios.Singleton.CheckToken(request.Email, token);
return (esValido) ? if (esValido) {
Ok( new { esValido = true}) : Unauthorized( new {esValido = false}); return Ok(new {esValido = esValido});
} else {
return Unauthorized(new {esValido = "el token no es valido"});
}
} }
+18
View File
@@ -0,0 +1,18 @@
#if DEBUG
using Microsoft.AspNetCore.Mvc;
using Modelo;
namespace AlquilaFacil.Controllers;
[ApiController]
public class PermisosController: ControllerBase {
[HttpPost("api/admin/permisos")]
public IActionResult CrearPermisos([FromBody] AdminPermiso permiso) {
if (String.IsNullOrEmpty(permiso.descripcion)) return BadRequest();
bool ret = RepositorioPermisos.Singleton.CrearPermiso(permiso.descripcion);
return (ret) ? Ok(ret) : BadRequest();
}
}
public record AdminPermiso(string descripcion);
#endif
+8
View File
@@ -0,0 +1,8 @@
namespace Entidades.Dto;
public class InquilinoDto {
public long Dni { get; set; }
public string Nombre { get; set; } = "";
public string Apellido { get; set; } = "";
}
+1 -3
View File
@@ -1,9 +1,7 @@
using System.ComponentModel.DataAnnotations.Schema;
namespace Entidades.Dto; namespace Entidades.Dto;
public class LoginDto public class LoginDto
{ {
public string Email {get; set;} = string.Empty; public string Email {get; set;} = string.Empty;
public string Contraseña {get; set;} = string.Empty; public string? Contraseña {get; set;} = string.Empty;
} }
+30 -15
View File
@@ -1,44 +1,59 @@
<script lang="ts"> <script lang="ts">
import { Navbar, NavbarBrand, NavbarToggler, NavItem, Nav, NavLink, Collapse } from "@sveltestrap/sveltestrap"; import { Navbar, NavbarBrand, NavbarToggler, NavItem, Nav, NavLink, Collapse } from "@sveltestrap/sveltestrap";
import { onMount } from "svelte"; import { onMount } from "svelte";
import { navigate } from "svelte-routing"; import { writable } from 'svelte/store';
let isOpen = false;
function handleUpdate(event: any) { let isOpen: boolean = $state(false);
isOpen = event.detail.isOpen;
interface Permiso {
id: number;
descripcion: string;
} }
let permisos = $state() const permisos = writable<Permiso[]>([]);
const email = localStorage.getItem('email');
const token = sessionStorage.getItem('token');
async function obtenerPermisos(){ async function obtenerPermisos(){
try { try {
const response = await fetch("http://localhost:5007/api/acciones",{ const response = await fetch("http://localhost:5007/api/acciones",{
method: 'POST', method: 'POST',
headers: { headers: {
'Auth' : String(token),
'Content-Type' : "application/json" 'Content-Type' : "application/json"
}, },
credentials: 'include' body: JSON.stringify({email})
}); });
if (response.ok){ if (response.ok){
permisos = response.json(); const json = await response.json();
permisos.set(json);
} }
} catch (e) { } catch (e) {
console.error(e); console.error(e);
navigate("/");
} }
} }
onMount(async () => { $inspect(permisos);
onMount( () => {
obtenerPermisos();
}) })
</script> </script>
<Navbar container="xxl" expand="md" color="dark-subtle"> <Navbar container="xxl" expand="md" color="dark-subtle">
<NavbarBrand href="/Menu">AlquilaFacil</NavbarBrand> <NavbarBrand href="/">
AlquilaFacil
</NavbarBrand>
<NavbarToggler on:click={() => (isOpen = !isOpen)} /> <NavbarToggler on:click={() => (isOpen = !isOpen)} />
<Collapse isOpen={isOpen} navbar expand="md" on:update={handleUpdate}> <Collapse isOpen={isOpen} navbar expand="md">
<Nav class="ms-auto" navbar> <Nav class="ms-auto" navbar>
{#each $permisos as item }
<NavItem>
<NavLink href="/accion/{item.id}">{item.descripcion}</NavLink>
</NavItem>
{/each}
</Nav> </Nav>
</Collapse> </Collapse>
</Navbar> </Navbar>
+4 -5
View File
@@ -1,9 +1,8 @@
<script lang="ts"> <script lang="ts">
import { Navbar, NavbarBrand, NavbarToggler, NavItem, Nav, NavLink, Collapse } from "@sveltestrap/sveltestrap"; import { Navbar, NavbarBrand, NavbarToggler, NavItem, Nav, NavLink, Collapse } from "@sveltestrap/sveltestrap";
let isOpen = $state(false);
function handleUpdate(event) { let isOpen:boolean = false;
isOpen = event.detail.isOpen;
}
</script> </script>
@@ -12,7 +11,7 @@
AlquilaFacil AlquilaFacil
</NavbarBrand> </NavbarBrand>
<NavbarToggler on:click={() => (isOpen = !isOpen)} /> <NavbarToggler on:click={() => (isOpen = !isOpen)} />
<Collapse isOpen={isOpen} navbar expand="md" on:update={handleUpdate}> <Collapse isOpen={isOpen} navbar expand="md">
<Nav class="ms-auto" navbar> <Nav class="ms-auto" navbar>
<NavItem> <NavItem>
<NavLink href="/">Login</NavLink> <NavLink href="/">Login</NavLink>
+37 -35
View File
@@ -1,51 +1,53 @@
<script> <script>
import { onMount } from 'svelte'; import { onMount } from 'svelte';
import { navigate } from 'svelte-routing'; // Asumiendo que estás usando svelte-routing import { navigate } from 'svelte-routing';
import { writable } from 'svelte/store'; import { writable } from 'svelte/store';
let isAuthenticated = writable(false); export let component;
let isVerified = writable(false);
const isAuthenticated = writable(false);
const isVerified = writable(false);
let { component } = $props(); const redirect = window.location.pathname;
const email = localStorage.getItem('email');
const token = sessionStorage.getItem('token');
let redirect = window.location.pathname; const handleAccess = async () => {
const email = localStorage.getItem('email');
const handleAccess = async () => {
try { try {
const response = await fetch('http://127.0.0.1:5007/api/login/validar', { const response = await fetch('http://127.0.0.1:5007/api/login/validar', {
method: 'POST', method: 'POST',
headers: { headers: {
'Content-Type': 'application/json', 'Auth': String(token),
}, 'Content-Type': 'application/json',
body: JSON.stringify( {email, redirect} ), },
credentials: "include" body: JSON.stringify({ email, redirect }),
}); credentials: "include"
});
if (response.ok) { if (response.ok) {
isAuthenticated.set(true); isAuthenticated.set(true); // Actualiza el store
} }
} catch (error) {
console.error('Error durante la autenticación:', error);
} finally { } finally {
isVerified.set(true); isVerified.set(true); // Marca la verificación como completada
} }
}; };
onMount(async () => { onMount(() => {
await handleAccess(); handleAccess();
}); });
</script> </script>
{#if !$isVerified} {#if !$isVerified}
<div class="spinner-border position-absolute top-50 start-50 translate-middle" role="status"> <div class="spinner-border position-absolute top-50 start-50 translate-middle" role="status">
<span class="visually-hidden">Cargando</span> <span class="visually-hidden">Cargando</span>
</div> </div>
{:else} {:else}
{#if $isAuthenticated} {#if $isAuthenticated}
{@const SvelteComponent = component} <svelte:component this={component} />
<SvelteComponent/>
{:else} {:else}
{navigate('/')} {navigate('/')}
{/if} {/if}
{/if} {/if}
+1
View File
@@ -32,6 +32,7 @@
const ret = await response.json(); const ret = await response.json();
localStorage.clear(); localStorage.clear();
localStorage.setItem('email', ret.email); localStorage.setItem('email', ret.email);
sessionStorage.setItem('token', ret.token);
//setTimeout(() => console.log("50ms") ,50); //setTimeout(() => console.log("50ms") ,50);
navigate(ret.redirect); navigate(ret.redirect);
} catch (e) { } catch (e) {
+1 -1
View File
@@ -17,5 +17,5 @@
"moduleDetection": "force" "moduleDetection": "force"
}, },
"include": ["src/**/*.ts", "src/**/*.js", "src/**/*.svelte"], "include": ["src/**/*.ts", "src/**/*.js", "src/**/*.svelte"],
"references": [{ "path": "./tsconfig.json" }] "references": [{ "path": "./tsconfig.node.json" }]
} }
+25
View File
@@ -0,0 +1,25 @@
#if DEBUG
using Entidades;
namespace Modelo;
public class RepositorioGrupos: RepositorioBase<RepositorioGrupos> {
public bool CrearGrupo(string descripcion)
{
var con = Context;
int mx = con.Grupos.Max(grupo => grupo.Id);
Grupo gru = new Grupo{
Id = mx+1,
Nombre = descripcion,
};
con.Grupos.Add(gru);
return Guardar(con);
}
}
#endif
+17
View File
@@ -0,0 +1,17 @@
using Entidades.Dto;
using Microsoft.EntityFrameworkCore;
namespace Modelo;
public class RepositorioInquilinos: RepositorioBase<RepositorioInquilinos> {
public IQueryable<InquilinoDto> GetInquilinos()
{
FormattableString sqlq =
$"""
SELECT I.Dni, I.Nombre, I.Apellido FROM Inquilinos
""";
return Context.Database.SqlQuery<InquilinoDto>(sqlq);
}
}
+42 -1
View File
@@ -1,3 +1,4 @@
using System.Text.RegularExpressions;
using Entidades; using Entidades;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
@@ -14,6 +15,46 @@ public class RepositorioPermisos: RepositorioBase<RepositorioPermisos> {
.SelectMany(g => g.Idpermisos) .SelectMany(g => g.Idpermisos)
.Distinct(); .Distinct();
return list; return list;
} }
public bool CheckPermisos(string token, string path){
var con = Context;
//checkeo que el token corresponda a un usuario
Cliente? cli = con.Clientes.FirstOrDefault(x => x.Token == token);
if (cli == null || cli.Dni == 0) return false;
// obtengo una lista de los permisos
var permisos = con.Clientes
.Where(x => x.Dni == cli.Dni)
.SelectMany(x => x.Idgrupos)
.SelectMany(x => x.Idpermisos)
.Distinct();
//me inspiré y hice un regex pero si eliminaba los primeros 8(?) caracteres del string era lo mismo
Match match = Regex.Match(path, @"^/accion/(\d+)$");
int.TryParse(match.Groups[1].Value, out int idpermiso);
bool tienePermiso = false;
Parallel.ForEach(permisos, (x, i) =>{
if (x.Id == idpermiso) {
tienePermiso = true;
}
});
return tienePermiso;
}
#if DEBUG
public bool CrearPermiso(string descripcion) {
var con = Context;
int mx = con.Permisos.Max(x => x.Id);
Permiso per = new Permiso{
Id = mx,
Descripcion = descripcion
};
con.Permisos.Add(per);
return Guardar(con);
}
#endif
} }
+4
View File
@@ -57,6 +57,10 @@ public class RepositorioUsuarios: RepositorioBase<RepositorioUsuarios>
var usu = Context.Clientes.FirstOrDefault(x => x.Email == email); var usu = Context.Clientes.FirstOrDefault(x => x.Email == email);
if (usu == null) return false; if (usu == null) return false;
#if DEBUG
//Console.WriteLine(token + "\n" +usu.Token);
#endif
return usu.Token == token; return usu.Token == token;
} }