From 41198e568a6a39854762b76ccfd05b99ba0759a2 Mon Sep 17 00:00:00 2001 From: Samuel Modesto Date: Thu, 24 Jul 2025 17:32:21 -0300 Subject: [PATCH 1/2] ajuste para que o id do user e da accommodation seja unico na arquitetura --- .../java/com/example/rent/dto/AccommodationDto.java | 2 +- .../main/java/com/example/rent/dto/BookingDto.java | 2 +- .../src/main/java/com/example/rent/dto/UserDto.java | 2 +- .../com/example/rent/entities/Accommodation.java | 7 +++++-- .../main/java/com/example/rent/entities/User.java | 9 ++++++--- .../main/java/com/example/rent/enums/UserType.java | 6 +++--- .../java/com/example/rent/mapper/BookingMapper.java | 2 +- .../example/rent/receiver/AccommodationReceiver.java | 1 + .../java/com/example/rent/receiver/UserReceiver.java | 1 + .../rent/repository/AccommodationRepository.java | 2 +- .../com/example/rent/repository/UserRepository.java | 2 +- .../com/example/rent/resources/BookingResource.java | 2 +- .../example/rent/service/AccommodationService.java | 2 +- .../com/example/rent/service/BookingService.java | 2 +- .../java/com/example/rent/service/UserService.java | 2 +- .../rent/service/impl/AccommodationServiceImpl.java | 2 +- .../rent/service/impl/BookingServiceImpl.java | 2 +- .../example/rent/service/impl/UserServiceImpl.java | 2 +- .../service/impl/AccommodationServiceImplTest.java | 12 ++++++------ 19 files changed, 35 insertions(+), 27 deletions(-) diff --git a/transacional/src/main/java/com/example/rent/dto/AccommodationDto.java b/transacional/src/main/java/com/example/rent/dto/AccommodationDto.java index b4d6899b..eadb9752 100644 --- a/transacional/src/main/java/com/example/rent/dto/AccommodationDto.java +++ b/transacional/src/main/java/com/example/rent/dto/AccommodationDto.java @@ -3,6 +3,6 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; @JsonIgnoreProperties(ignoreUnknown = true) -public record AccommodationDto(Double price, int maxOccupancy) { +public record AccommodationDto(String id, Double price, int maxOccupancy) { } diff --git a/transacional/src/main/java/com/example/rent/dto/BookingDto.java b/transacional/src/main/java/com/example/rent/dto/BookingDto.java index 7af398c8..e6020bdf 100644 --- a/transacional/src/main/java/com/example/rent/dto/BookingDto.java +++ b/transacional/src/main/java/com/example/rent/dto/BookingDto.java @@ -3,5 +3,5 @@ import java.time.LocalDate; import java.util.List; -public record BookingDto(Long accommodationId, List guestIds, LocalDate intialDate, LocalDate endDate) { +public record BookingDto(String accommodationId, List guestIds, LocalDate intialDate, LocalDate endDate) { } diff --git a/transacional/src/main/java/com/example/rent/dto/UserDto.java b/transacional/src/main/java/com/example/rent/dto/UserDto.java index 6a37ff25..42ad9ca1 100644 --- a/transacional/src/main/java/com/example/rent/dto/UserDto.java +++ b/transacional/src/main/java/com/example/rent/dto/UserDto.java @@ -4,7 +4,7 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; @JsonIgnoreProperties(ignoreUnknown = true) -public record UserDto(String name, String email, UserType type) { +public record UserDto(String id, String name, String email, UserType type) { } diff --git a/transacional/src/main/java/com/example/rent/entities/Accommodation.java b/transacional/src/main/java/com/example/rent/entities/Accommodation.java index af08bbc6..000169ed 100644 --- a/transacional/src/main/java/com/example/rent/entities/Accommodation.java +++ b/transacional/src/main/java/com/example/rent/entities/Accommodation.java @@ -8,6 +8,7 @@ import lombok.NoArgsConstructor; +import java.io.Serial; import java.io.Serializable; @Entity @@ -17,9 +18,11 @@ @Builder public class Accommodation implements Serializable { + @Serial + private static final long serialVersionUID = 6742147475962430968L; + @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - private Long id; + private String id; private Double price; diff --git a/transacional/src/main/java/com/example/rent/entities/User.java b/transacional/src/main/java/com/example/rent/entities/User.java index 0341aadb..331440e4 100644 --- a/transacional/src/main/java/com/example/rent/entities/User.java +++ b/transacional/src/main/java/com/example/rent/entities/User.java @@ -7,8 +7,8 @@ import lombok.Data; import lombok.NoArgsConstructor; +import java.io.Serial; import java.io.Serializable; -import java.util.List; @Entity @Data @@ -17,15 +17,18 @@ @Builder public class User implements Serializable { + @Serial + private static final long serialVersionUID = -9206949953784522451L; + @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - private Long id; + private String id; private String name; private String email; @Enumerated(EnumType.STRING) + @Column(name = "user_type", length = 30, nullable = false) private UserType userType; } diff --git a/transacional/src/main/java/com/example/rent/enums/UserType.java b/transacional/src/main/java/com/example/rent/enums/UserType.java index 476761d8..e70f393d 100644 --- a/transacional/src/main/java/com/example/rent/enums/UserType.java +++ b/transacional/src/main/java/com/example/rent/enums/UserType.java @@ -4,11 +4,11 @@ public enum UserType { - HOST, + ROLE_HOST, - GUEST, + ROLE_GUEST, - ADMINISTRATOR; + ROLE_ADMINISTRATOR; @JsonCreator public static UserType fromString(String value) { diff --git a/transacional/src/main/java/com/example/rent/mapper/BookingMapper.java b/transacional/src/main/java/com/example/rent/mapper/BookingMapper.java index c1045903..b16a8d3f 100644 --- a/transacional/src/main/java/com/example/rent/mapper/BookingMapper.java +++ b/transacional/src/main/java/com/example/rent/mapper/BookingMapper.java @@ -24,7 +24,7 @@ public static Booking toEntity(BookingDto dto, Accommodation accommodation, List } public static BookingDto toDto(Booking booking) { - List guestIds = booking.getGuests().stream() + List guestIds = booking.getGuests().stream() .map(guestBooking -> guestBooking.getGuest().getId()) .toList(); diff --git a/transacional/src/main/java/com/example/rent/receiver/AccommodationReceiver.java b/transacional/src/main/java/com/example/rent/receiver/AccommodationReceiver.java index 634075f5..1aeed817 100644 --- a/transacional/src/main/java/com/example/rent/receiver/AccommodationReceiver.java +++ b/transacional/src/main/java/com/example/rent/receiver/AccommodationReceiver.java @@ -24,6 +24,7 @@ public AccommodationReceiver(AccommodationRepository accommodationRepository) { @RabbitListener(queues = {"${crud.rabbitmq.queues.accommodationQueue}"}) public void receive(@Payload AccommodationDto dto) { Accommodation accommodation = new Accommodation(); + accommodation.setId(dto.id()); accommodation.setPrice(dto.price()); accommodation.setStatus(StatusAccommodation.AVAILABLE); accommodation.setGuestCapacity(dto.maxOccupancy()); diff --git a/transacional/src/main/java/com/example/rent/receiver/UserReceiver.java b/transacional/src/main/java/com/example/rent/receiver/UserReceiver.java index 559bf68a..c7626acb 100644 --- a/transacional/src/main/java/com/example/rent/receiver/UserReceiver.java +++ b/transacional/src/main/java/com/example/rent/receiver/UserReceiver.java @@ -21,6 +21,7 @@ public UserReceiver(UserRepository userRepository) { @RabbitListener(queues = {"${crud.rabbitmq.queues.userQueue}"}) public void receive(@Payload UserDto dto) { User user = new User(); + user.setId(dto.id()); user.setName(dto.name()); user.setEmail(dto.email()); user.setUserType(dto.type()); diff --git a/transacional/src/main/java/com/example/rent/repository/AccommodationRepository.java b/transacional/src/main/java/com/example/rent/repository/AccommodationRepository.java index 9df90b96..9a2b2eed 100644 --- a/transacional/src/main/java/com/example/rent/repository/AccommodationRepository.java +++ b/transacional/src/main/java/com/example/rent/repository/AccommodationRepository.java @@ -9,6 +9,6 @@ import java.util.UUID; @Repository -public interface AccommodationRepository extends JpaRepository { +public interface AccommodationRepository extends JpaRepository { } diff --git a/transacional/src/main/java/com/example/rent/repository/UserRepository.java b/transacional/src/main/java/com/example/rent/repository/UserRepository.java index 0e1e41c7..dd25fd6d 100644 --- a/transacional/src/main/java/com/example/rent/repository/UserRepository.java +++ b/transacional/src/main/java/com/example/rent/repository/UserRepository.java @@ -7,6 +7,6 @@ import java.util.UUID; @Repository -public interface UserRepository extends JpaRepository { +public interface UserRepository extends JpaRepository { } diff --git a/transacional/src/main/java/com/example/rent/resources/BookingResource.java b/transacional/src/main/java/com/example/rent/resources/BookingResource.java index dfe26ab8..cc70de62 100644 --- a/transacional/src/main/java/com/example/rent/resources/BookingResource.java +++ b/transacional/src/main/java/com/example/rent/resources/BookingResource.java @@ -69,7 +69,7 @@ public ResponseEntity cancelBookingById(@PathVariable Long id) throw @PatchMapping("/{id}/pay/{userId}") @Operation(summary = "Realiza o pagamento de uma reserva") - public ResponseEntity payBooking(@PathVariable Long id, @PathVariable Long userId) throws Exception { + public ResponseEntity payBooking(@PathVariable Long id, @PathVariable String userId) throws Exception { BookingDto bookingDto = bookingService.payBooking(id, userId); return ResponseEntity.ok(bookingDto); } diff --git a/transacional/src/main/java/com/example/rent/service/AccommodationService.java b/transacional/src/main/java/com/example/rent/service/AccommodationService.java index 17794c6d..abc10f85 100644 --- a/transacional/src/main/java/com/example/rent/service/AccommodationService.java +++ b/transacional/src/main/java/com/example/rent/service/AccommodationService.java @@ -5,7 +5,7 @@ import java.util.Optional; public interface AccommodationService { - Optional findAccommodationById(Long id); + Optional findAccommodationById(String id); void changeStatusForRented(Accommodation accommodation); } diff --git a/transacional/src/main/java/com/example/rent/service/BookingService.java b/transacional/src/main/java/com/example/rent/service/BookingService.java index 424df0c8..fdd0fe90 100644 --- a/transacional/src/main/java/com/example/rent/service/BookingService.java +++ b/transacional/src/main/java/com/example/rent/service/BookingService.java @@ -12,5 +12,5 @@ public interface BookingService { Booking updateBooking(Booking request) throws Exception; - BookingDto payBooking(Long bookingId, Long userId) throws Exception; + BookingDto payBooking(Long bookingId, String userId) throws Exception; } diff --git a/transacional/src/main/java/com/example/rent/service/UserService.java b/transacional/src/main/java/com/example/rent/service/UserService.java index 8b2e55e7..819ed6a9 100644 --- a/transacional/src/main/java/com/example/rent/service/UserService.java +++ b/transacional/src/main/java/com/example/rent/service/UserService.java @@ -7,6 +7,6 @@ public interface UserService { - Optional findById(Long id); + Optional findById(String id); } diff --git a/transacional/src/main/java/com/example/rent/service/impl/AccommodationServiceImpl.java b/transacional/src/main/java/com/example/rent/service/impl/AccommodationServiceImpl.java index f83232b1..fd5304b0 100644 --- a/transacional/src/main/java/com/example/rent/service/impl/AccommodationServiceImpl.java +++ b/transacional/src/main/java/com/example/rent/service/impl/AccommodationServiceImpl.java @@ -15,7 +15,7 @@ public class AccommodationServiceImpl implements AccommodationService { private final AccommodationRepository accommodationRepository; @Override - public Optional findAccommodationById(Long id) { + public Optional findAccommodationById(String id) { return accommodationRepository.findById(id); } diff --git a/transacional/src/main/java/com/example/rent/service/impl/BookingServiceImpl.java b/transacional/src/main/java/com/example/rent/service/impl/BookingServiceImpl.java index fda65eba..6e966362 100644 --- a/transacional/src/main/java/com/example/rent/service/impl/BookingServiceImpl.java +++ b/transacional/src/main/java/com/example/rent/service/impl/BookingServiceImpl.java @@ -144,7 +144,7 @@ public Booking updateBooking(Booking request) throws Exception { } @Override - public BookingDto payBooking(Long bookingId, Long userId) throws Exception { + public BookingDto payBooking(Long bookingId, String userId) throws Exception { Booking booking = getBookingById(bookingId); if (booking.getStatusReservation() == StatusReservation.CANCELED diff --git a/transacional/src/main/java/com/example/rent/service/impl/UserServiceImpl.java b/transacional/src/main/java/com/example/rent/service/impl/UserServiceImpl.java index 6f9dd9f8..bcd2e795 100644 --- a/transacional/src/main/java/com/example/rent/service/impl/UserServiceImpl.java +++ b/transacional/src/main/java/com/example/rent/service/impl/UserServiceImpl.java @@ -15,7 +15,7 @@ public class UserServiceImpl implements UserService { private final UserRepository userRepository; - public Optional findById(Long id) { + public Optional findById(String id) { return userRepository.findById(id); } diff --git a/transacional/src/test/java/com/example/rent/service/impl/AccommodationServiceImplTest.java b/transacional/src/test/java/com/example/rent/service/impl/AccommodationServiceImplTest.java index a940826d..0b685cb9 100644 --- a/transacional/src/test/java/com/example/rent/service/impl/AccommodationServiceImplTest.java +++ b/transacional/src/test/java/com/example/rent/service/impl/AccommodationServiceImplTest.java @@ -36,24 +36,24 @@ void setUp() { @Test void testFindAccommodationByIdSuccess() { - when(accommodationRepository.findById(1L)).thenReturn(Optional.of(mockAccommodation)); + when(accommodationRepository.findById("abc")).thenReturn(Optional.of(mockAccommodation)); - Optional result = accommodationService.findAccommodationById(1L); + Optional result = accommodationService.findAccommodationById("abc"); assertTrue(result.isPresent()); assertEquals(1L, result.get().getId()); assertEquals(500.00, result.get().getPrice()); - verify(accommodationRepository, times(1)).findById(1L); + verify(accommodationRepository, times(1)).findById("abc"); } @Test void testFindAccommodationByIdNotFound() { - when(accommodationRepository.findById(2L)).thenReturn(Optional.empty()); + when(accommodationRepository.findById("xyz")).thenReturn(Optional.empty()); - Optional result = accommodationService.findAccommodationById(2L); + Optional result = accommodationService.findAccommodationById("xyz"); assertFalse(result.isPresent()); - verify(accommodationRepository, times(1)).findById(2L); + verify(accommodationRepository, times(1)).findById("xyz"); } @Test From 623f73a2363fc253eacbb6af89cc809083ee06ad Mon Sep 17 00:00:00 2001 From: Samuel Modesto Date: Mon, 28 Jul 2025 15:06:14 -0300 Subject: [PATCH 2/2] =?UTF-8?q?autentica=C3=A7=C3=A3o=20para=20o=20micross?= =?UTF-8?q?ervi=C3=A7o=20transacional?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../crud/config/security/JwtProvider.java | 7 ++ transacional/pom.xml | 14 ++++ .../security/JwtAuthenticationFilter.java | 50 +++++++++++++ .../rent/config/security/JwtProvider.java | 45 +++++++++++ .../rent/config/security/SecurityConfig.java | 44 +++++++++++ .../rent/config/security/SecurityUtil.java | 34 +++++++++ .../rent/config/security/UserDatailsImpl.java | 75 +++++++++++++++++++ .../rent/resources/BookingResource.java | 13 +++- .../impl/AccommodationServiceImplTest.java | 2 +- 9 files changed, 279 insertions(+), 5 deletions(-) create mode 100644 transacional/src/main/java/com/example/rent/config/security/JwtAuthenticationFilter.java create mode 100644 transacional/src/main/java/com/example/rent/config/security/JwtProvider.java create mode 100644 transacional/src/main/java/com/example/rent/config/security/SecurityConfig.java create mode 100644 transacional/src/main/java/com/example/rent/config/security/SecurityUtil.java create mode 100644 transacional/src/main/java/com/example/rent/config/security/UserDatailsImpl.java diff --git a/cadastral/src/main/java/com/unipampa/crud/config/security/JwtProvider.java b/cadastral/src/main/java/com/unipampa/crud/config/security/JwtProvider.java index 6d2c80e2..f56fad24 100644 --- a/cadastral/src/main/java/com/unipampa/crud/config/security/JwtProvider.java +++ b/cadastral/src/main/java/com/unipampa/crud/config/security/JwtProvider.java @@ -7,6 +7,7 @@ import org.springframework.stereotype.Component; import java.util.Date; +import java.util.stream.Collectors; @Log4j2 @Component @@ -20,8 +21,14 @@ public class JwtProvider { public String generateJwtToken(Authentication authentication) { UserDatailsImpl userPrincipal = (UserDatailsImpl) authentication.getPrincipal(); + + final String roles = userPrincipal.getAuthorities().stream().map(role -> { + return role.getAuthority(); + }).collect(Collectors.joining()); + return Jwts.builder() .setSubject(userPrincipal.getUserId()) + .claim("roles", roles) .setIssuedAt(new Date()) .setExpiration(new Date((new Date()).getTime() + jwtExpirationMs)) .signWith(io.jsonwebtoken.SignatureAlgorithm.HS512, jwtSecret) diff --git a/transacional/pom.xml b/transacional/pom.xml index 1a5ba7e0..b8164699 100644 --- a/transacional/pom.xml +++ b/transacional/pom.xml @@ -32,6 +32,20 @@ target/site/jacoco/jacoco.xml + + org.springframework.boot + spring-boot-starter-security + + + io.jsonwebtoken + jjwt + 0.9.1 + + + javax.xml.bind + jaxb-api + 2.3.1 + org.springframework.boot spring-boot-starter-amqp diff --git a/transacional/src/main/java/com/example/rent/config/security/JwtAuthenticationFilter.java b/transacional/src/main/java/com/example/rent/config/security/JwtAuthenticationFilter.java new file mode 100644 index 00000000..9f8d5416 --- /dev/null +++ b/transacional/src/main/java/com/example/rent/config/security/JwtAuthenticationFilter.java @@ -0,0 +1,50 @@ +package com.example.rent.config.security; + +import jakarta.servlet.FilterChain; +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.stereotype.Component; +import org.springframework.web.filter.OncePerRequestFilter; + +import java.io.IOException; + +@Component +public class JwtAuthenticationFilter extends OncePerRequestFilter { + + @Autowired + private JwtProvider jwtProvider; + + @Override + protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { + String token = extractToken(request); + if (token != null && jwtProvider.validateToken(token)) { + String userId = jwtProvider.getSubjectFromToken(token); + logger.info("username extraído do token: " + userId); + + String roleStr = jwtProvider.getClaimNameJwt(token, "roles"); + UserDetails userDetails = UserDatailsImpl.build(userId, roleStr); + logger.info("user details encontrado: " + userDetails); + + UsernamePasswordAuthenticationToken authentication = + new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities()); + + SecurityContextHolder.getContext().setAuthentication(authentication); + } + + filterChain.doFilter(request, response); + + } + + private String extractToken(HttpServletRequest request) { + String authHeader = request.getHeader("Authorization"); + if (authHeader != null && authHeader.startsWith("Bearer ")) { + return authHeader.substring(7); + } + return null; + } +} diff --git a/transacional/src/main/java/com/example/rent/config/security/JwtProvider.java b/transacional/src/main/java/com/example/rent/config/security/JwtProvider.java new file mode 100644 index 00000000..ff117ae1 --- /dev/null +++ b/transacional/src/main/java/com/example/rent/config/security/JwtProvider.java @@ -0,0 +1,45 @@ +package com.example.rent.config.security; + +import io.jsonwebtoken.*; +import lombok.extern.log4j.Log4j2; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +@Log4j2 +@Component +public class JwtProvider { + + @Value( "${ead.auth.jwtSecret}") + private String jwtSecret; + + public String getSubjectFromToken(String token) { + return Jwts.parser() + .setSigningKey(jwtSecret) + .parseClaimsJws(token) + .getBody() + .getSubject(); + } + + public String getClaimNameJwt(String token, String claimName) { + return Jwts.parser().setSigningKey(jwtSecret).parseClaimsJws(token).getBody().get(claimName, String.class); + } + + public boolean validateToken(String authToken) { + try { + Jwts.parser().setSigningKey(jwtSecret).parseClaimsJws(authToken); + return true; + + } catch (SignatureException e) { + log.error("Invalid JWT signature: {}", e.getMessage()); + } catch (MalformedJwtException e) { + log.error("Invalid JWT token: {}", e.getMessage()); + } catch (ExpiredJwtException e) { + log.error("JWT token is expired: {}", e.getMessage()); + } catch (UnsupportedJwtException e) { + log.error("JWT token is unsupported: {}", e.getMessage()); + } catch (IllegalArgumentException e) { + log.error("JWT claims string is empty: {}", e.getMessage()); + } + return false; + } +} diff --git a/transacional/src/main/java/com/example/rent/config/security/SecurityConfig.java b/transacional/src/main/java/com/example/rent/config/security/SecurityConfig.java new file mode 100644 index 00000000..9d940135 --- /dev/null +++ b/transacional/src/main/java/com/example/rent/config/security/SecurityConfig.java @@ -0,0 +1,44 @@ +package com.example.rent.config.security; + +import jakarta.ws.rs.HttpMethod; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.authentication.AuthenticationManager; +import org.springframework.security.config.Customizer; +import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; +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.configurers.AbstractHttpConfigurer; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.security.web.SecurityFilterChain; +import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; + +@Configuration +@EnableMethodSecurity +public class SecurityConfig { + + @Autowired + private JwtAuthenticationFilter jwtAuthenticationFilter; + + @Bean + public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { + http + .csrf(AbstractHttpConfigurer::disable) + .authorizeHttpRequests(auth -> auth + .requestMatchers(HttpMethod.POST, "/users/**", "/auth/**").permitAll() + .requestMatchers(HttpMethod.GET, "/accommodations", "/accommodations/**", "/images/**").permitAll() + .anyRequest().authenticated() + ) + .addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class) + .httpBasic(Customizer.withDefaults()); + + return http.build(); + } + + @Bean + public PasswordEncoder passwordEncoder() { + return new BCryptPasswordEncoder(); + } +} \ No newline at end of file diff --git a/transacional/src/main/java/com/example/rent/config/security/SecurityUtil.java b/transacional/src/main/java/com/example/rent/config/security/SecurityUtil.java new file mode 100644 index 00000000..5b572d0b --- /dev/null +++ b/transacional/src/main/java/com/example/rent/config/security/SecurityUtil.java @@ -0,0 +1,34 @@ +package com.example.rent.config.security; + +import org.springframework.security.core.Authentication; +import org.springframework.security.core.authority.SimpleGrantedAuthority; +import org.springframework.security.core.context.SecurityContextHolder; + +public class SecurityUtil { + + public static String getAuthenticatedUserId() { + Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); + + if (authentication != null && authentication.getPrincipal() instanceof UserDatailsImpl userDetails) { + return userDetails.getUserId(); + } + + throw new RuntimeException("Usuário não autenticado!"); + } + + public static boolean isAuthenticatedAdmin() { + Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); + + if (authentication != null && authentication.getAuthorities().contains(new SimpleGrantedAuthority("ROLE_ADMINISTRATOR"))) { + return true; + } + return false; + } + + public static boolean isOwnerOrAdmin(String resourceUserId) { + String authenticatedUserId = getAuthenticatedUserId(); + return isAuthenticatedAdmin() || authenticatedUserId.equals(resourceUserId); + } + + +} \ No newline at end of file diff --git a/transacional/src/main/java/com/example/rent/config/security/UserDatailsImpl.java b/transacional/src/main/java/com/example/rent/config/security/UserDatailsImpl.java new file mode 100644 index 00000000..9c151f86 --- /dev/null +++ b/transacional/src/main/java/com/example/rent/config/security/UserDatailsImpl.java @@ -0,0 +1,75 @@ +package com.example.rent.config.security; + +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.authority.SimpleGrantedAuthority; +import org.springframework.security.core.userdetails.UserDetails; + +import java.io.Serial; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; +import java.util.stream.Collectors; + +public class UserDatailsImpl implements UserDetails { + + @Serial + private static final long serialVersionUID = 4735505087197006457L; + private String userId; + private Collection authorities; + + public UserDatailsImpl(String userId, Collection authorities) { + this.userId = userId; + this.authorities = authorities; + } + + public static UserDatailsImpl build(String userId, String roleStr) { + List authorities = Arrays.stream(roleStr.split(",")) + .map(SimpleGrantedAuthority::new) + .collect(Collectors.toList()); + + return new UserDatailsImpl( + userId, + authorities + ); + } + + @Override + public Collection getAuthorities() { + return this.authorities; + } + + @Override + public String getPassword() { + return null; + } + + @Override + public String getUsername() { + return null; + } + + @Override + public boolean isAccountNonExpired() { + return true; + } + + @Override + public boolean isAccountNonLocked() { + return true; + } + + @Override + public boolean isCredentialsNonExpired() { + return true; + } + + @Override + public boolean isEnabled() { + return true; + } + + public String getUserId() { + return userId; + } + +} diff --git a/transacional/src/main/java/com/example/rent/resources/BookingResource.java b/transacional/src/main/java/com/example/rent/resources/BookingResource.java index cc70de62..eb8699a6 100644 --- a/transacional/src/main/java/com/example/rent/resources/BookingResource.java +++ b/transacional/src/main/java/com/example/rent/resources/BookingResource.java @@ -14,6 +14,8 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.security.core.Authentication; import org.springframework.web.bind.annotation.*; import jakarta.validation.Valid; @@ -39,19 +41,22 @@ public class BookingResource { + @PreAuthorize("hasAnyRole('ROLE_ADMINISTRATOR', 'ROLE_GUEST')") @PostMapping @Operation(summary = "Cria uma reserva para uma propriedade existente") - public ResponseEntity createBooking(@RequestBody BookingDto request) { + public ResponseEntity createBooking(@RequestBody BookingDto request, Authentication authentication) { Booking response = bookingService.createBooking(request); return ResponseEntity.status(HttpStatus.CREATED).body(response); } + @PreAuthorize("hasAnyRole('ROLE_ADMINISTRATOR', 'ROLE_GUEST')") @PostMapping("/checkin/{idBooking}") @Operation(summary = "Faz checkin em uma reserva existente") public ResponseEntity checkin(@PathVariable @Valid Long idBooking) { return new ResponseEntity<>(rentService.processCheckin(idBooking), HttpStatus.CREATED); } + @PreAuthorize("hasAnyRole('ROLE_ADMINISTRATOR', 'ROLE_GUEST', 'ROLE_HOST')") @Operation(summary = "Consulta uma reserva existente") @GetMapping("/{id}") public ResponseEntity getBookingById(@PathVariable Long id) throws Exception { @@ -60,6 +65,7 @@ public ResponseEntity getBookingById(@PathVariable Long id) throws E return ResponseEntity.ok(BookingMapper.toDto(booking)); } + @PreAuthorize("hasAnyRole('ROLE_ADMINISTRATOR', 'ROLE_GUEST', 'ROLE_HOST')") @Operation(summary = "Cancela uma reserva existente") @PatchMapping("/{id}/cancel") public ResponseEntity cancelBookingById(@PathVariable Long id) throws Exception { @@ -67,6 +73,7 @@ public ResponseEntity cancelBookingById(@PathVariable Long id) throw return ResponseEntity.ok(BookingMapper.toDto(booking)); } + @PreAuthorize("hasAnyRole('ROLE_ADMINISTRATOR', 'ROLE_GUEST')") @PatchMapping("/{id}/pay/{userId}") @Operation(summary = "Realiza o pagamento de uma reserva") public ResponseEntity payBooking(@PathVariable Long id, @PathVariable String userId) throws Exception { @@ -74,6 +81,7 @@ public ResponseEntity payBooking(@PathVariable Long id, @PathVariabl return ResponseEntity.ok(bookingDto); } + @PreAuthorize("hasRole('ROLE_ADMINISTRATOR')") @PostMapping("/forcar/cancelamento/{idReserva}") public ResponseEntity forcarCancelamento(@PathVariable Long idReserva) { Optional reservaOptional = bookingRepository.findById(idReserva); @@ -87,7 +95,4 @@ public ResponseEntity forcarCancelamento(@PathVariable Long idReserva) { return ResponseEntity.status(404).body("Reserva com ID " + idReserva + " não encontrada."); } } - - - } diff --git a/transacional/src/test/java/com/example/rent/service/impl/AccommodationServiceImplTest.java b/transacional/src/test/java/com/example/rent/service/impl/AccommodationServiceImplTest.java index 0b685cb9..18ea4a79 100644 --- a/transacional/src/test/java/com/example/rent/service/impl/AccommodationServiceImplTest.java +++ b/transacional/src/test/java/com/example/rent/service/impl/AccommodationServiceImplTest.java @@ -29,7 +29,7 @@ class AccommodationServiceImplTest { @BeforeEach void setUp() { mockAccommodation = new Accommodation(); - mockAccommodation.setId(1L); + mockAccommodation.setId("abc"); mockAccommodation.setPrice(500.00); }