> For the complete documentation index, see [llms.txt](https://abi.gitbook.io/net-core/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://abi.gitbook.io/net-core/7.-seguridad/7.2-seguridad-basada-en-roles/7.5-creando-tu-tabla-usuarios.md).

# 9.2.3 Creando las tablas para manejar la seguridad

#### Creando nuestra tabla Usuarios

Siguiendo las recomendaciones de seguridad de la lección anterior voy a crear la tabla usuarios de la siguiente manera:

{% code title="Usuario.cs" %}

```csharp
public class Usuario
{
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int Id { get; set; }

    [Required(ErrorMessage = "Required")]
    [StringLength(15, ErrorMessage = "StringLength")]
    [Column(TypeName = "VARCHAR(15)")]
    public string Clave { get; set; }

    [Required(ErrorMessage = "Required")]
    [StringLength(255, ErrorMessage = "StringLength")]
    [Column(TypeName = "VARCHAR(255)")]
    public string Password { get; set; }

    [Required(ErrorMessage = "Required")]
    public bool Activo { get; set; }

    [Required(ErrorMessage = "Required")]
    public string Adicional1 { get; set; }

    [Required(ErrorMessage = "Required")]
    [StringLength(200, ErrorMessage = "StringLength")]
    [Column(TypeName = "VARCHAR(200)")]
    public string Nombre { get; set; }

    [Required(ErrorMessage = "Required")]
    [StringLength(80, ErrorMessage = "StringLength")]
    [Column(TypeName = "VARCHAR(80)")]
    public string Email { get; set; }
}
```

{% endcode %}

Agregamos un indice único para la clave del usuario

{% code title="UsuarioConfiguration.cs" %}

```csharp
public class : IEntityTypeConfiguration<Usuario>
{
    public void Configure(EntityTypeBuilder<Usuario> builder)
    {
         builder.HasIndex(e => e.Clave)
                .HasName("UI_UsuarioClave")
                .IsUnique();
    }
}
```

{% endcode %}

#### Creando nuestra tabla UsuarioAcceso

Agregamos nuestra tabla UsuarioAcceso para registrar los accesos de nuestros usuarios, como el navegador, ciudad, estado, país, sistema operativo desde donde inicia sesión el usuario

{% code title="UsuarioAcceso.cs" %}

```csharp
public class UsuarioAcceso
{
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int Id { get; set; }

    [Required(ErrorMessage = "Required")]
    public int UsuarioId { get; set; }

    [Required(ErrorMessage = "Required")]
    public DateTime Fecha { get; set; }

    [Column(TypeName = "VARCHAR(300)")]
    [Required(ErrorMessage = "Required")]
    public string Token { get; set; }

    [Required(ErrorMessage = "Required")]
    public bool Activo { get; set; }

    [Required(ErrorMessage = "Required")]
    [Column(TypeName = "VARCHAR(200)")]
    public string SistemaOperativo { get; set; }

    [Required(ErrorMessage = "Required")]
    [Column(TypeName = "VARCHAR(200)")]
    public string Navegador { get; set; }

    [Required(ErrorMessage = "Required")]
    [StringLength(300, ErrorMessage = "StringLength")]
    [Column(TypeName = "VARCHAR(300)")]
    public string Ciudad { get; set; }

    [Required(ErrorMessage = "Required")]
    [StringLength(300, ErrorMessage = "StringLength")]
    [Column(TypeName = "VARCHAR(300)")]
    public string Estado { get; set; }

    [Required(ErrorMessage = "Required")]
    [Column(TypeName = "VARCHAR(200)")]
    public string RefreshToken { get; set; }

    [Required(ErrorMessage = "Required")]
    public DateTime FechaRefresh { get; set; }

    [Required(ErrorMessage = "Required")]
    public bool MantenerSesion { get; set; }
    
}
```

{% endcode %}

Creamos nuestras llaves foráneas e índices. Vamos a agregar un índice para el campo refresh token, y otro para el usuario y el token

{% code title="UsuarioAccesoConfiguration.cs" %}

```csharp
public class UsuarioAccesoConfiguration 
                         : IEntityTypeConfiguration<UsuarioAcceso>
{
    public void Configure(EntityTypeBuilder<UsuarioAcceso> builder)
    {
        builder.HasOne(typeof(Usuario))
               .WithMany()
               .OnDelete(DeleteBehavior.Restrict);
                   
        builder.HasIndex(u => u.RefreshToken)
               .HasName("UI_RefreshToken")
               .IsUnique();

        builder.HasIndex(u => new { u.UsuarioId, u.Token })
               .HasName("UI_Token")
               .IsUnique();
    }
}
```

{% endcode %}

#### Creando nuestra tabla UsuarioRol

En esta tabla vamos a guardar todos los roles que tiene un usuario. Esto permite a un mismo usuario poder accesar como vendedor, administrador o cliente.

{% code title="UsuarioRol.cs" %}

```csharp
public class UsuarioRol
{
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int Id { get; set; }

    [Required(ErrorMessage = "Required")]
    public int UsuarioId { get; set; }

    [Required(ErrorMessage = "Required")]
    public int RolId { get; set; }
}
```

{% endcode %}

Agregamos nuestra llaves foráneas e índices

{% code title="UsuarioRolConfiguration.cs" %}

```csharp
public class UsuarioRolConfiguration 
                                 : IEntityTypeConfiguration<UsuarioRol>
{
    public void Configure(EntityTypeBuilder<UsuarioRol> builder)
    {
        builder.HasIndex(u => new { u.UsuarioId, u.RolId })
               .HasName("UI_UsuarioRol")
               .IsUnique();

        builder.HasOne(typeof(Usuario))
               .WithMany()
               .OnDelete(DeleteBehavior.Restrict);

        builder.HasOne(typeof(Rol))
               .WithMany()
               .OnDelete(DeleteBehavior.Restrict);
    }
}
```

{% endcode %}

#### Agregando la tabla UsuarioCliente

Esta tabla nos permitirá registrar los usuarios que tiene cada cliente, de esta manera un usuario no puede ver los productos de otro cliente.

{% code title="UsuarioCliente.cs" %}

```csharp
public class UsuarioCliente
{
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int Id { get; set; }

    [Required(ErrorMessage = "Required")]
    public int UsuarioId { get; set; }

    [Required(ErrorMessage = "Required")]
    public int ClienteId { get; set; }
}
```

{% endcode %}

Agregamos nuestras llaves foráneas e índices

{% code title="UsuarioClienteConfiguration.cs" %}

```csharp
public class UsuarioClienteConfiguration 
                         : IEntityTypeConfiguration<UsuarioCliente>
{
    public void Configure(EntityTypeBuilder<UsuarioCliente> builder)
    {
        builder.HasIndex(u => new { u.UsuarioId, u.ClienteId })
           .HasName("UI_UsuarioCliente")
           .IsUnique();

        builder.HasOne(typeof(Usuario))
               .WithMany()
               .OnDelete(DeleteBehavior.Restrict);

        builder.HasOne(typeof(Cliente))
               .WithMany()
               .OnDelete(DeleteBehavior.Restrict);
    }
}
```

{% endcode %}

#### Agregando nuestra tabla Tabla

Para cada tabla registrada en el sistema, vamos a guardar un historial de cambios realizados a la tabla, en el cual vamos a guardar la fecha y hora en que se agrega, borra o modifica un registro, el usuario que realizó el cambio al registro, observaciones adicionales sobre el cambio realizado, y la tabla en que se realiza el cambio, para esto voy a registrar en una tabla llamada **tabla** los datos de la tabla que se esta modificando

{% code title="Tabla.cs" %}

```csharp
public class Tabla
{
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int Id { get; set; }

    [Required(ErrorMessage = "Required")]
    [StringLength(40, ErrorMessage = "StringLength")]
    [Column(TypeName = "VARCHAR(40)")]
    public string Nombre { get; set; }

    [Required(ErrorMessage = "Required")]
    [StringLength(40, ErrorMessage = "StringLength")]
    [Column(TypeName = "VARCHAR(200)")]
    public string Descripción { get; set; }
}
```

{% endcode %}

#### Agregando nuestra tabla historial

```csharp
public class Historial
{
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int Id { get; set; }

    [Required(ErrorMessage = "Required")]
    public int TablaId { get; set; }

    [Required(ErrorMessage = "Required")]
    public int OrigenId { get; set; }

    [Required(ErrorMessage = "Required")]
    public int Actividad { get; set; }

    [Required(ErrorMessage = "Required")]
    [ForeignKey("Usuario")]
    public int? UsuarioId { get; set; }

    [Required(ErrorMessage = "Required")]
    public DateTime FechaHora { get; set; }

    [StringLength(250, ErrorMessage = "StringLength")]
    [Column(TypeName = "VARCHAR(250)")]
    public string Observa { get; set; }
}
```

Agregamos nuestras llaves foráneas e índices

{% code title="HistorialConfiguration.cs" %}

```csharp
public class HistorialConfiguration : IEntityTypeConfiguration<Historial>
{
    public void Configure(EntityTypeBuilder<Historial> builder)
    {
        builder.HasIndex(h => h.TablaId)
               .HasName("IX_HistorialTabla");

        builder.HasIndex(e => e.UsuarioId)
               .HasName("IX_ctrUsuario");

        builder.HasIndex(e => new { e.Actividad, e.TablaId, e.FechaHora })
               .HasName("IX_Actividad");

        builder.HasIndex(e => new { e.TabladId, e.OrigenId, e.Actividad })
               .HasName("IX_Historial");

        builder.HasOne(typeof(Tabla))
               .WithMany()
               .OnDelete(DeleteBehavior.Restrict);

        builder.HasOne(typeof(Usuario))
            .WithMany()
            .OnDelete(DeleteBehavior.Restrict);
    }
}
```

{% endcode %}

Agregamos nuestras tablas y archivos de configuración a nuestro archivo **CaducaContext**

{% code title="CaducaContext.cs" %}

```csharp
public class CaducaContext : DbContext
{
    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.ApplyConfiguration(new HistorialConfiguration());
        modelBuilder.ApplyConfiguration(new UsuarioAccesoConfiguration());
        modelBuilder.ApplyConfiguration(new UsuarioClienteConfiguration());
        modelBuilder.ApplyConfiguration(new UsuarioConfiguration());
        modelBuilder.ApplyConfiguration(new UsuarioRolConfiguration());        
        
        public virtual DbSet<Historial> Historial { get; set; }
        public virtual DbSet<Tabla> Tabla { get; set; }
        public virtual DbSet<Usuario> Usuario { get; set; }
        public virtual DbSet<UsuarioAcceso> UsuarioAcceso { get; set; }
        public virtual DbSet<UsuarioCliente> UsuarioCliente { get; set; }
        public virtual DbSet<UsuarioRol> UsuarioRol { get; set; }
    } 
}
```

{% endcode %}

Agregamos nuestra migración

```
Add-Migration TablasSeguridad
```

Actualizamos nuestra base de datos

```
Update-Database
```
