No tienes acceso a esta clase

¡Continúa aprendiendo! Únete y comienza a potenciar tu carrera

Asignar roles a usuario

14/23
Recursos

¿Cómo gestionar roles de usuario en Spring con Hibernate?

En el desarrollo de aplicaciones web seguras, la gestión de usuarios y roles es una pieza fundamental. Esta guía te proporciona una base sólida para implementar y administrar roles de usuario en tus aplicaciones usando Spring y Hibernate. Exploraremos cómo crear y asignar roles a usuarios dentro de una base de datos MySQL y cómo conectar este sistema a un User Detail Service en Spring.

¿Cómo crear la tabla de roles de usuario?

Para comenzar, vamos a crear una tabla en MySQL que gestione los roles. Esta tabla se llamará User_Role y estará relacionada con la tabla User. Aquí tienes una idea de cómo debería ser su estructura:

  • Username: Viene de la tabla User.
  • Role: Será uno de los roles asignados.
  • Granted Date: Indica desde cuándo el rol ha sido asignado.

Puedes crear esta tabla usando Hibernate o directamente con un script SQL en tu base de datos MySQL. Este enfoque asegura que cada usuario pueda tener distintos roles, reflejando una relación de uno a muchos (one-to-many).

¿Cómo implementar las entidades en tu proyecto?

Dentro de tu proyecto de Spring, deberás implementar la entidad UserRoleEntity. Aquí es donde definiremos cómo se relacionan los usuarios con los roles:

public class UserRoleEntity {
    @IdClass(UserRoleId.class)
    private String username;
    private String role;
    private LocalDate grantedDate;
    
    @ManyToOne
    @JoinColumn(name = "user_id")
    private UserEntity user;
    
    // Getters, setters, equals, and hashCode methods
}

La entidad UserRoleEntity implementa una clave primaria compuesta por username y role, reflejando su naturaleza de relación en la base de datos.

En UserEntity, incorpora una lista de UserRoleEntity anotada con @OneToMany. Asegúrate de configurar la carga FetchType.EAGER para que los roles se carguen automáticamente al recuperar un usuario.

@OneToMany(mappedBy = "user", fetch = FetchType.EAGER)
private List<UserRoleEntity> roles;

¿Cómo asignar roles y verificar el acceso?

Una vez que la aplicación está configurada y la tabla creada, es hora de asignar roles a usuarios. Puedes realizar esta operación directamente en MySQL Workbench:

  1. Asigna el rol Admin al usuario admin y un rol Customer al usuario correspondiente.
  2. Asegúrate de utilizar la función now() de MySQL para registrar correctamente la fecha actual en Granted Date.

Finalmente, en tu implementación del UserDetailService, reemplaza la lista de roles inicial con los roles obtenidos de la base de datos. Convierte los roles a un arreglo de cadenas de caracteres, utilizándolos para autenticar y autorizar a los usuarios.

String[] roles = userEntity.getRoles()
    .stream()
    .map(UserRoleEntity::getRole)
    .toArray(String[]::new);

De esta manera, puedes controlar el acceso a los diferentes endpoints de tu API, asegurándote de que solo aquellos usuarios con los permisos necesarios puedan realizar ciertas acciones.

¿Qué hacer en caso de bloqueos de cuenta?

Además de asignar roles, tienes la capacidad de bloquear usuarios temporalmente si fuera necesario. Esto se gestiona mediante una propiedad locked, la cual, al activarse, impide que el usuario acceda al sistema aunque sus credenciales sean correctas:

UPDATE user SET locked = 1 WHERE username = 'admin';

Esta funcionalidad es crucial para asegurar tu aplicación contra accesos indebidos o para manejar situaciones de seguridad específicas.

Con esta estructura, aseguras que tu aplicación no solo sea segura, sino también flexible, permitiendo una administración detallada de los recursos y accesos según los roles de usuario establecidos.

Aportes 8

Preguntas 4

Ordenar por:

¿Quieres ver más aportes, preguntas y respuestas de la comunidad?

Inserts:


insert into user_role (username, role, granted_date)
values ('admin','ADMIN',NOW());

insert into user_role (username, role, granted_date)
values ('customer','CUSTOMER',NOW());
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

import java.io.Serializable;
import java.util.Objects;

@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public class UserRoleId implements Serializable {
    private String username;
    private String role;

    @Override
    public boolean equals(Object obj) {
        if (this == obj) return true;
        if (!(obj instanceof UserRoleId that)) return false;
        return Objects.equals(username, that.username) && Objects.equals(role, that.role);
    }

    @Override
    public int hashCode() {
        return Objects.hash(username, role);
    }
}
package com.platzi.pizza.persistence.entity;

import jakarta.persistence.*;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

import java.time.LocalDateTime;

@Entity
@Table(name = "user_role")
@IdClass(UserRoleId.class)
@Getter
@Setter
@NoArgsConstructor
public class UserRoleEntity {

    @Id
    @Column(nullable = false, length = 20)
    private String username;

    @Id
    @Column(nullable = false, length = 20)
    private String role;

    @Column(name = "granted_date", nullable = false, columnDefinition = "DATETIME")
    private LocalDateTime grantedDate;

    @ManyToOne
    @JoinColumn(name = "username", referencedColumnName = "username", insertable = false, updatable = false)
    private UserEntity user;
}

UserRoleEntity ```js package com.platzi.pizzeria.persistence.entity; import jakarta.persistence.*; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; import java.time.LocalDateTime; @Entity @Table(name = "user_role") @IdClass(UserRoleId.class) @Getter @Setter @NoArgsConstructor public class UserRoleEntity { @Id @Column(nullable = false, length = 20) private String username; @Id @Column(nullable = false, length = 20) private String role; @Column(name = "granted_date", nullable = false, columnDefinition = "DATETIME") private LocalDateTime grantedDate; @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "username", referencedColumnName = "username", insertable = false, updatable = false) private UserEntity user; } ``` U ```js package com.platzi.pizzeria.persistence.entity; import jakarta.persistence.*; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; import java.util.List; @Entity @Table(name = "user") @Getter @Setter @NoArgsConstructor public class UserEntity { @Id @Column(nullable = false, length = 20) private String username; @Column(nullable = false, length = 200) private String password; @Column(length = 50) private String email; @Column(nullable = false, columnDefinition = "TINYINT") private Boolean locked; @Column(nullable = false, columnDefinition = "TINYINT") private Boolean disabled; @OneToMany(mappedBy = "user", fetch = FetchType.EAGER) private List<UserRoleEntity> roles; } ``` UserRoleId ```js package com.platzi.pizzeria.persistence.entity; import lombok.AllArgsConstructor; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; import java.io.Serializable; import java.util.Objects; @Getter @Setter @NoArgsConstructor @AllArgsConstructor public class UserRoleId implements Serializable { private String username; private String role; @Override public boolean equals(Object o) { if(this == o) return true; if(!(o instanceof UserRoleId that)) return false; return Objects.equals(username, that.username) && Objects.equals(role, that.role); } @Override public int hashCode() { return Objects.hash(username, role); } } ``` UserSecuriryService ```js package com.platzi.pizzeria.service; import com.platzi.pizzeria.persistence.entity.UserEntity; import com.platzi.pizzeria.persistence.entity.UserRoleEntity; import com.platzi.pizzeria.persistence.repository.UserRepository; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.core.userdetails.User; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.stereotype.Service; @Service public class UserSecurityService implements UserDetailsService { private final UserRepository userRepository; @Autowired public UserSecurityService(UserRepository userRepository) { this.userRepository = userRepository; } @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { UserEntity userEntity = this.userRepository.findById(username) .orElseThrow(() -> new UsernameNotFoundException("User + " + username + " NOT FOUND")); String[] roles = userEntity.getRoles().stream().map(UserRoleEntity::getRole).toArray(String[]::new); return User.builder() .username(userEntity.getUsername()) .password(userEntity.getPassword()) .roles(roles) .accountLocked(userEntity.getLocked()) .disabled(userEntity.getDisabled()) .build(); } } ```
Otra forma de convertir un objeto del tipo List\<T> a un objeto del tipo T\[]: ```java String[] roles = userEntity.getRoles().toArray(new String[userEntity.getRoles().size()]); ```String\[] roles = userEntity.getRoles().toArray(new String\[userEntity.getRoles().size()]);
Otra forma de convertir un objeto de tipo List\<T> a un array del tipo T\[]: `String[] roles = userEntity.getRoles().toArray(new String[userEntity.getRoles().size()]);`

package com.platzi.pizza.persistence.entity;

import jakarta.persistence.*;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

import java.util.List;

@Entity
@Table(name = "user")
@Getter
@Setter
@NoArgsConstructor
public class UserEntity {
    @Id
    @Column(nullable = false, length = 20)
    private String username;

    @Column(nullable = false, length = 200)
    private String password;

    @Column(length = 50)
    private String email;

    @Column(nullable = false, columnDefinition = "TINYINT")
    private Boolean locked;

    @Column(nullable = false, columnDefinition = "TINYINT")
    private Boolean disabled;

    @OneToMany(mappedBy = "user", fetch = FetchType.EAGER)
    private List<UserRoleEntity> roles;
}