diff --git a/src/main/java/com/litoralregas/backend_gateway/config/SecurityConfig.java b/src/main/java/com/litoralregas/backend_gateway/config/SecurityConfig.java index dbd77f6..43fe4d5 100644 --- a/src/main/java/com/litoralregas/backend_gateway/config/SecurityConfig.java +++ b/src/main/java/com/litoralregas/backend_gateway/config/SecurityConfig.java @@ -1,15 +1,21 @@ package com.litoralregas.backend_gateway.config; +import com.litoralregas.backend_gateway.security.JwtAuthenticationFilter; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.web.builders.HttpSecurity; 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 public class SecurityConfig { + private final JwtAuthenticationFilter jwtAuthenticationFilter; + public SecurityConfig(JwtAuthenticationFilter jwtAuthenticationFilter) { + this.jwtAuthenticationFilter = jwtAuthenticationFilter; + } @Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { return http @@ -17,6 +23,7 @@ public class SecurityConfig { .authorizeHttpRequests(auth -> auth .anyRequest().permitAll() ) + .addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class) .build(); } diff --git a/src/main/java/com/litoralregas/backend_gateway/security/AuthDebugController.java b/src/main/java/com/litoralregas/backend_gateway/security/AuthDebugController.java new file mode 100644 index 0000000..3ed58bc --- /dev/null +++ b/src/main/java/com/litoralregas/backend_gateway/security/AuthDebugController.java @@ -0,0 +1,18 @@ +package com.litoralregas.backend_gateway.security; + +import org.springframework.security.core.Authentication; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +public class AuthDebugController { + + @GetMapping("/debug/me") + public Object me(Authentication authentication) { + if (authentication == null) { + return "anonymous"; + } + + return authentication.getPrincipal(); + } +} \ No newline at end of file diff --git a/src/main/java/com/litoralregas/backend_gateway/security/AuthenticatedUser.java b/src/main/java/com/litoralregas/backend_gateway/security/AuthenticatedUser.java new file mode 100644 index 0000000..af1ce5e --- /dev/null +++ b/src/main/java/com/litoralregas/backend_gateway/security/AuthenticatedUser.java @@ -0,0 +1,11 @@ +package com.litoralregas.backend_gateway.security; + +import com.litoralregas.backend_gateway.user.UserRole; + +public record AuthenticatedUser( + Long userId, + Long clientId, + String username, + UserRole role +) { +} \ No newline at end of file diff --git a/src/main/java/com/litoralregas/backend_gateway/security/JwtAuthenticationFilter.java b/src/main/java/com/litoralregas/backend_gateway/security/JwtAuthenticationFilter.java new file mode 100644 index 0000000..3d78d1c --- /dev/null +++ b/src/main/java/com/litoralregas/backend_gateway/security/JwtAuthenticationFilter.java @@ -0,0 +1,70 @@ +package com.litoralregas.backend_gateway.security; + +import com.litoralregas.backend_gateway.user.UserRole; +import jakarta.servlet.FilterChain; +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.authority.SimpleGrantedAuthority; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.stereotype.Component; +import org.springframework.web.filter.OncePerRequestFilter; + +import java.io.IOException; +import java.util.List; + +@Component +public class JwtAuthenticationFilter extends OncePerRequestFilter { + + private final JwtService jwtService; + + public JwtAuthenticationFilter(JwtService jwtService) { + this.jwtService = jwtService; + } + + @Override + protected void doFilterInternal( + HttpServletRequest request, + HttpServletResponse response, + FilterChain filterChain + ) throws ServletException, IOException { + + String authHeader = request.getHeader("Authorization"); + + if (authHeader == null || !authHeader.startsWith("Bearer ")) { + filterChain.doFilter(request, response); + return; + } + + String token = authHeader.substring(7); + + if (!jwtService.isValid(token)) { + filterChain.doFilter(request, response); + return; + } + + String username = jwtService.extractUsername(token); + Long userId = jwtService.extractUserId(token); + Long clientId = jwtService.extractClientId(token); + UserRole role = UserRole.valueOf(jwtService.extractRole(token)); + + AuthenticatedUser authenticatedUser = new AuthenticatedUser( + userId, + clientId, + username, + role + ); + + UsernamePasswordAuthenticationToken authentication = + new UsernamePasswordAuthenticationToken( + authenticatedUser, + null, + List.of(new SimpleGrantedAuthority("ROLE_" + role.name())) + ); + + SecurityContextHolder.getContext().setAuthentication(authentication); + + filterChain.doFilter(request, response); + } +} \ No newline at end of file diff --git a/src/main/java/com/litoralregas/backend_gateway/security/JwtService.java b/src/main/java/com/litoralregas/backend_gateway/security/JwtService.java index 466e773..94f8246 100644 --- a/src/main/java/com/litoralregas/backend_gateway/security/JwtService.java +++ b/src/main/java/com/litoralregas/backend_gateway/security/JwtService.java @@ -83,4 +83,19 @@ public class JwtService { public String extractRole(String token) { return getClaims(token).get("role", String.class); } + + public Long extractUserId(String token) { + + Object value = getClaims(token).get("userId"); + + if (value instanceof Integer integer) { + return integer.longValue(); + } + + if (value instanceof Long longValue) { + return longValue; + } + + return Long.parseLong(value.toString()); + } } \ No newline at end of file