No tienes acceso a esta clase

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

Controlar métodos con Method Security

16/23
Recursos

Aportes 6

Preguntas 1

Ordenar por:

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

Durante la introducción de este curso se hizo alusión a un caso de uso real y muy importante que -en mi entender- iba a ser resuelto durante el desarrollo del mismo.

Validar la identidad del usuario e identificar sus privilegios se llevó a cabo, lo que no se llevó a cabo fue abordar el caso de uso descrito: ¿Como diseñar e implementar la seguridad para que un usuario, sólo pueda ver sus movimientos y no así los movimientos de otros usuarios? Hay que tomar en cuenta que Roles “ADMIN” pudieran ver los movimientos de cualquier usuario o existan otros roles que agrupen movimientos de varios usuarios pero no todos…

Esto se podría ilustrar con las órdenes, permitiendo que el customer en cuestión pueda visualizar sus órdenes pero no las de otro customer, y también que un admin pueda visualizar todas.

Pregunta de examen:
¿Cómo implementarían ésto? Me gustaría ver sus approaches e ideas para ello, les comparto un approach básico para éste caso de uso, posteriormente les comparto el approach específico a este, tomen en cuenta lo siguiente que ya se ha visto en éste curso:

Autenticación de Usuarios:
Implementa la autenticación de usuarios utilizando Spring Security. Puedes utilizar autenticación basada en tokens JWT (JSON Web Tokens) o sesiones, según tus necesidades.

  1. Autorización Basada en Roles:
    Define roles de usuario para diferentes niveles de acceso en tu sistema. Por ejemplo, podrías tener roles como “USER” y “ADMIN”. Asegúrate de que cada usuario tenga asignado uno o más roles.

  2. Personalización de Usuarios:
    Extiende el objeto de usuario proporcionado por Spring Security para incluir información adicional, como el ID del usuario, su nombre, etc.

  3. Limitar el Acceso a Recursos:
    Implementa una capa de autorización personalizada utilizando anotaciones @PreAuthorize o @PostAuthorize en tus controladores. Esto permitirá definir condiciones específicas para acceder a ciertos recursos.

  4. Diseño de Endpoints:
    Diseña tus endpoints de manera que los recursos sensibles (como los movimientos de Israel) sean accesibles solo por usuarios con roles y permisos adecuados.

  5. Configuración de Seguridad:
    En la configuración de Spring Security, define reglas de autorización detalladas utilizando expresiones SpEL (Spring Expression Language) dentro de las anotaciones @PreAuthorize o @PostAuthorize.

@RestController
@RequestMapping("/movimientos")
public class MovimientosController {

    @GetMapping("/{usuario}")
    @PreAuthorize("#usuario == authentication.principal.username") // Solo el usuario autenticado puede acceder a sus propios movimientos
    public ResponseEntity<List<Movimiento>> getMovimientos(@PathVariable String usuario) {
        // Implementa la lógica para obtener los movimientos del usuario
    }

    @GetMapping("/{usuario}/{id}")
    @PreAuthorize("#usuario == authentication.principal.username") // Solo el usuario autenticado puede acceder a su propio movimiento
    public ResponseEntity<Movimiento> getMovimiento(@PathVariable String usuario, @PathVariable Long id) {
        // Implementa la lógica para obtener un movimiento específico del usuario
    }
}

Traslademos lo anterior al caso de uso de orders para la pizzeria.

Saludos; Nunca pares de aprender.

Hasta ahora el proyecto está corriendo normal… 🙏 espero terminar así, jajaja.

Solo los usuarios a cualquier nivel tienen permisos adecuados donde solo podrán ejecutar determinadas acciones. De esta manera proteger los controladores y las reglas de negocio del proyecto.

CustomerController ```java package com.platzi.pizzeria.web.controller; import com.platzi.pizzeria.persistence.entity.CustomerEntity; import com.platzi.pizzeria.persistence.entity.OrderEntity; import com.platzi.pizzeria.service.CustomerService; import com.platzi.pizzeria.service.OrderService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import java.util.List; @RestController @RequestMapping("/api/customers") public class CustomerController { private final CustomerService customerService; private final OrderService orderService; @Autowired public CustomerController(CustomerService customerService, OrderService orderService) { this.customerService = customerService; this.orderService = orderService; } @GetMapping("/phone/{phone}") public ResponseEntity<CustomerEntity> getByPhone(@PathVariable String phone) { return ResponseEntity.ok(customerService.findByPhone(phone)); } @GetMapping("/orders/{id}") public ResponseEntity<List<OrderEntity>> getCustomerOrders(@PathVariable String id){ return ResponseEntity.ok(this.orderService.getCustomerOrders(id)); } } ``` UserSecurityService ```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.GrantedAuthority; import org.springframework.security.core.authority.SimpleGrantedAuthority; 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; import java.util.ArrayList; import java.util.List; @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()) .authorities(this.grantedAuthorities(roles)) .accountLocked(userEntity.getLocked()) .disabled(userEntity.getDisabled()) .build(); } private String[] getAuthorities(String role) { if("ADMIN".equals(role) || "CUSTOMER".equals(role)) { return new String[] {"random_order"}; } return new String[] {}; } private List<GrantedAuthority> grantedAuthorities(String[] roles) { List<GrantedAuthority> authorities = new ArrayList<>(roles.length); for(String role: roles) { authorities.add(new SimpleGrantedAuthority("ROLE_" + role)); for(String authority: this.getAuthorities(role)) { authorities.add(new SimpleGrantedAuthority(authority)); } } return authorities; } } ``` Securiry Config ```java package com.platzi.pizzeria.web.config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.http.HttpMethod; import org.springframework.security.config.Customizer; import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.web.SecurityFilterChain; @Configuration @EnableMethodSecurity(securedEnabled = true) public class SecurityConfig { @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http .csrf(AbstractHttpConfigurer::disable) .cors(Customizer.withDefaults()) .authorizeHttpRequests((authorize) -> authorize .requestMatchers("/api/customers/**").hasAnyRole("ADMIN", "CUSTOMER") .requestMatchers(HttpMethod.GET, "/api/pizzas/**").hasAnyRole("ADMIN", "CUSTOMER") .requestMatchers(HttpMethod.POST, "/api/pizzas/**").hasRole("ADMIN") .requestMatchers(HttpMethod.PUT).hasRole("ADMIN") .requestMatchers("/api/orders/random").hasAuthority("random_order") .requestMatchers("/api/orders/**").hasRole("ADMIN") .anyRequest() .authenticated() ) .httpBasic(Customizer.withDefaults()) ; return http.build(); } @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } } ``` OrderService ```js package com.platzi.pizzeria.service; import com.platzi.pizzeria.persistence.entity.OrderEntity; import com.platzi.pizzeria.persistence.projection.OrderSumary; import com.platzi.pizzeria.persistence.repository.OrderRepository; import com.platzi.pizzeria.service.dto.RandomOrderDto; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.access.annotation.Secured; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.time.LocalDate; import java.time.LocalDateTime; import java.util.Arrays; import java.util.List; @Service public class OrderService { private final OrderRepository orderRepository; private static final String DELIVERY = "D"; private static final String CARRYOUT = "C"; private static final String ON_SITE = "S"; @Autowired public OrderService(OrderRepository orderRepository) { this.orderRepository = orderRepository; } public List<OrderEntity> getAll(){ List<OrderEntity> orders = this.orderRepository.findAll(); orders.forEach(o -> System.out.println(o.getCustomer().getName())); return orders; } public List<OrderEntity> getTodayOrders() { LocalDateTime today = LocalDate.now().atTime(0,0); return this.orderRepository.findAllByDateAfter(today); } public List<OrderEntity> getOutsideOrders() { List<String> methods = Arrays.asList(DELIVERY, CARRYOUT); return this.orderRepository.findAllByMethodIn(methods); } @Secured("ROLE_ADMIN") public List<OrderEntity> getCustomerOrders(String idCustomer) { return this.orderRepository.findCustomerOrders(idCustomer); } public OrderSumary getSummary(int orderId) { return this.orderRepository.findSummary(orderId); } @Transactional public boolean saveRandomOrder(RandomOrderDto dto) { return this.orderRepository.saveRandomOrder(dto.getIdCustomer(), dto.getMethod()); } } ```
Si llegan a tener un error con el `EnableMethodSecurity` lo remplazan por `EnableGlobalMethodSecurity`