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

View File

@@ -1,3 +1,4 @@
using Entidades.Dto;
using Microsoft.AspNetCore.Mvc;
using Modelo;
@@ -7,14 +8,17 @@ namespace AlquilaFacil.Controllers;
public class AccionesController: ControllerBase {
[HttpPost("api/acciones")]
public IActionResult ListarAccionesPorUsuario([FromBody] string email) {
Request.Cookies.TryGetValue("token", out var token);
if (token == null) return Unauthorized(new { esValido = false});
public IActionResult ListarAccionesPorUsuario([FromBody] LoginDto email, [FromHeader(Name = "Auth")] string Auth) {
if (email.Email == "" || email.Email == null) return BadRequest();
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();
var Permisos = RepositorioPermisos.Singleton.ListarPermisos(email);
var Permisos = RepositorioPermisos.Singleton.ListarPermisos(email.Email);
Response.Headers["Content-Type"] = "application/json";
return Ok(Permisos);
}
}

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

View File

@@ -12,8 +12,16 @@ public class InquilinoController: ControllerBase
{
[HttpGet("api/inquilino")]
public IActionResult Get() {
return Ok();
public IActionResult Get([FromHeader(Name = "Auth")] string Auth) {
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")]

View File

@@ -24,19 +24,19 @@ public class LoginController: ControllerBase
var cookieOptions = new CookieOptions
{
HttpOnly = true,
Secure = true,
//SameSite = SameSiteMode.Strict,
Expires = DateTimeOffset.UtcNow.AddHours(1)
Secure = true,
SameSite = SameSiteMode.None,
Path = "/Menu",
Expires = DateTimeOffset.UtcNow.AddHours(1)
};
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")]
public IActionResult Verificar([FromBody] AccessDto request){
Request.Cookies.TryGetValue("token", out var token);
public IActionResult Verificar([FromBody] AccessDto request, [FromHeader(Name = "Auth")] string token){
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);
return (esValido) ?
Ok( new { esValido = true}) : Unauthorized( new {esValido = false});
if (esValido) {
return Ok(new {esValido = esValido});
} else {
return Unauthorized(new {esValido = "el token no es valido"});
}
}

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

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; } = "";
}

View File

@@ -1,9 +1,7 @@
using System.ComponentModel.DataAnnotations.Schema;
namespace Entidades.Dto;
public class LoginDto
{
public string Email {get; set;} = string.Empty;
public string Contraseña {get; set;} = string.Empty;
public string? Contraseña {get; set;} = string.Empty;
}

View File

@@ -1,44 +1,59 @@
<script lang="ts">
import { Navbar, NavbarBrand, NavbarToggler, NavItem, Nav, NavLink, Collapse } from "@sveltestrap/sveltestrap";
import { onMount } from "svelte";
import { navigate } from "svelte-routing";
let isOpen = false;
function handleUpdate(event: any) {
isOpen = event.detail.isOpen;
}
import { Navbar, NavbarBrand, NavbarToggler, NavItem, Nav, NavLink, Collapse } from "@sveltestrap/sveltestrap";
import { onMount } from "svelte";
import { writable } from 'svelte/store';
let permisos = $state()
let isOpen: boolean = $state(false);
interface Permiso {
id: number;
descripcion: string;
}
const permisos = writable<Permiso[]>([]);
const email = localStorage.getItem('email');
const token = sessionStorage.getItem('token');
async function obtenerPermisos(){
try {
const response = await fetch("http://localhost:5007/api/acciones",{
method: 'POST',
headers: {
'Auth' : String(token),
'Content-Type' : "application/json"
},
credentials: 'include'
body: JSON.stringify({email})
});
if (response.ok){
permisos = response.json();
const json = await response.json();
permisos.set(json);
}
} catch (e) {
console.error(e);
navigate("/");
}
}
onMount(async () => {
$inspect(permisos);
onMount( () => {
obtenerPermisos();
})
</script>
<Navbar container="xxl" expand="md" color="dark-subtle">
<NavbarBrand href="/Menu">AlquilaFacil</NavbarBrand>
<NavbarBrand href="/">
AlquilaFacil
</NavbarBrand>
<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>
{#each $permisos as item }
<NavItem>
<NavLink href="/accion/{item.id}">{item.descripcion}</NavLink>
</NavItem>
{/each}
</Nav>
</Collapse>
</Navbar>

View File

@@ -1,9 +1,8 @@
<script lang="ts">
import { Navbar, NavbarBrand, NavbarToggler, NavItem, Nav, NavLink, Collapse } from "@sveltestrap/sveltestrap";
let isOpen = $state(false);
function handleUpdate(event) {
isOpen = event.detail.isOpen;
}
let isOpen:boolean = false;
</script>
@@ -12,7 +11,7 @@
AlquilaFacil
</NavbarBrand>
<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>
<NavItem>
<NavLink href="/">Login</NavLink>

View File

@@ -1,51 +1,53 @@
<script>
import { onMount } from 'svelte';
import { navigate } from 'svelte-routing'; // Asumiendo que estás usando svelte-routing
import { writable } from 'svelte/store';
let isAuthenticated = writable(false);
let isVerified = writable(false);
let { component } = $props();
let redirect = window.location.pathname;
const email = localStorage.getItem('email');
const handleAccess = async () => {
import { onMount } from 'svelte';
import { navigate } from 'svelte-routing';
import { writable } from 'svelte/store';
export let component;
const isAuthenticated = writable(false);
const isVerified = writable(false);
const redirect = window.location.pathname;
const email = localStorage.getItem('email');
const token = sessionStorage.getItem('token');
const handleAccess = async () => {
try {
const response = await fetch('http://127.0.0.1:5007/api/login/validar', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify( {email, redirect} ),
credentials: "include"
});
if (response.ok) {
isAuthenticated.set(true);
}
const response = await fetch('http://127.0.0.1:5007/api/login/validar', {
method: 'POST',
headers: {
'Auth': String(token),
'Content-Type': 'application/json',
},
body: JSON.stringify({ email, redirect }),
credentials: "include"
});
if (response.ok) {
isAuthenticated.set(true); // Actualiza el store
}
} catch (error) {
console.error('Error durante la autenticación:', error);
} finally {
isVerified.set(true);
isVerified.set(true); // Marca la verificación como completada
}
};
onMount(async () => {
await handleAccess();
});
</script>
{#if !$isVerified}
};
onMount(() => {
handleAccess();
});
</script>
{#if !$isVerified}
<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>
{:else}
{:else}
{#if $isAuthenticated}
{@const SvelteComponent = component}
<SvelteComponent/>
<svelte:component this={component} />
{:else}
{navigate('/')}
{navigate('/')}
{/if}
{/if}
{/if}

View File

@@ -32,6 +32,7 @@
const ret = await response.json();
localStorage.clear();
localStorage.setItem('email', ret.email);
sessionStorage.setItem('token', ret.token);
//setTimeout(() => console.log("50ms") ,50);
navigate(ret.redirect);
} catch (e) {

View File

@@ -17,5 +17,5 @@
"moduleDetection": "force"
},
"include": ["src/**/*.ts", "src/**/*.js", "src/**/*.svelte"],
"references": [{ "path": "./tsconfig.json" }]
"references": [{ "path": "./tsconfig.node.json" }]
}

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

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);
}
}

View File

@@ -1,3 +1,4 @@
using System.Text.RegularExpressions;
using Entidades;
using Microsoft.EntityFrameworkCore;
@@ -14,6 +15,46 @@ public class RepositorioPermisos: RepositorioBase<RepositorioPermisos> {
.SelectMany(g => g.Idpermisos)
.Distinct();
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
}

View File

@@ -57,6 +57,10 @@ public class RepositorioUsuarios: RepositorioBase<RepositorioUsuarios>
var usu = Context.Clientes.FirstOrDefault(x => x.Email == email);
if (usu == null) return false;
#if DEBUG
//Console.WriteLine(token + "\n" +usu.Token);
#endif
return usu.Token == token;
}