diff --git a/pom.xml b/pom.xml index ee558f6..99a45db 100644 --- a/pom.xml +++ b/pom.xml @@ -47,7 +47,37 @@ 1.18.28 provided - + + + io.jsonwebtoken + jjwt + 0.9.1 + + + + javax.xml.bind + jaxb-api + 2.3.1 + + + org.glassfish.jaxb + jaxb-runtime + 2.3.1 + + + + + org.springframework.boot + spring-boot-starter-security + + + javax.servlet + javax.servlet-api + 4.0.1 + provided + + + diff --git a/src/main/java/com/health/app/AppApplication.java b/src/main/java/com/health/app/AppApplication.java index 742d339..213c5b2 100644 --- a/src/main/java/com/health/app/AppApplication.java +++ b/src/main/java/com/health/app/AppApplication.java @@ -1,5 +1,6 @@ package com.health.app; +import com.health.app.util.JwtUtil; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @@ -7,6 +8,7 @@ public class AppApplication { public static void main(String[] args) { + System.out.println( new JwtUtil().generateToken("admin")); SpringApplication.run(AppApplication.class, args); } diff --git a/src/main/java/com/health/app/config/SecurityConfig.java b/src/main/java/com/health/app/config/SecurityConfig.java new file mode 100644 index 0000000..0816e83 --- /dev/null +++ b/src/main/java/com/health/app/config/SecurityConfig.java @@ -0,0 +1,31 @@ +package com.health.app.config; + +import com.health.app.controller.filter.JwtFilter; +import lombok.RequiredArgsConstructor; +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.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer; +import org.springframework.security.web.SecurityFilterChain; +import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; + +@Configuration +@EnableWebSecurity +@RequiredArgsConstructor +public class SecurityConfig { + + private final JwtFilter jwtFilter; + @Bean + public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { + http + .csrf(AbstractHttpConfigurer::disable) // Desativar CSRF + .authorizeHttpRequests(auth -> auth + .requestMatchers("/user").permitAll() // Endpoints públicos + .anyRequest().authenticated() // Todos os outros endpoints são protegidos + ) + .addFilterBefore(jwtFilter, UsernamePasswordAuthenticationFilter.class); + + return http.build(); + } +} \ No newline at end of file diff --git a/src/main/java/com/health/app/config/WebConfig.java b/src/main/java/com/health/app/config/WebConfig.java index 45ab3fa..afcecc7 100644 --- a/src/main/java/com/health/app/config/WebConfig.java +++ b/src/main/java/com/health/app/config/WebConfig.java @@ -1,6 +1,7 @@ package com.health.app.config; import com.fasterxml.jackson.databind.ObjectMapper; +import com.health.app.controller.filter.JwtFilter; import com.health.app.integrations.openai.OpenAiClient; import lombok.SneakyThrows; import org.springframework.beans.factory.annotation.Value; diff --git a/src/main/java/com/health/app/controller/UserController.java b/src/main/java/com/health/app/controller/UserController.java index 9d9ec3d..8221039 100644 --- a/src/main/java/com/health/app/controller/UserController.java +++ b/src/main/java/com/health/app/controller/UserController.java @@ -5,6 +5,7 @@ import lombok.RequiredArgsConstructor; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController; @RestController @@ -14,7 +15,7 @@ public class UserController { private final UserService userService; @PostMapping("/user") - public ResponseEntity save(CreateUserRequestDTO requestDTO) { + public ResponseEntity save(@RequestBody CreateUserRequestDTO requestDTO) { userService.save(requestDTO); return ResponseEntity.ok("User created"); } diff --git a/src/main/java/com/health/app/controller/filter/JwtFilter.java b/src/main/java/com/health/app/controller/filter/JwtFilter.java new file mode 100644 index 0000000..7014895 --- /dev/null +++ b/src/main/java/com/health/app/controller/filter/JwtFilter.java @@ -0,0 +1,81 @@ +package com.health.app.controller.filter; + +import com.health.app.entity.User; +import com.health.app.repository.UserRepository; +import jakarta.servlet.FilterChain; +import jakarta.servlet.FilterConfig; +import jakarta.servlet.ServletException; +import jakarta.servlet.ServletRequest; +import jakarta.servlet.ServletResponse; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; + +import lombok.RequiredArgsConstructor; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.web.authentication.WebAuthenticationDetailsSource; +import org.springframework.stereotype.Component; +import org.springframework.web.filter.GenericFilterBean; + +import io.jsonwebtoken.Claims; +import io.jsonwebtoken.Jwts; + +import java.io.IOException; + +@Component +@RequiredArgsConstructor +public class JwtFilter extends GenericFilterBean { + + private final String secret = "secreto"; // Sua chave secreta + private final String prefix = "Bearer "; // Prefixo do token JWT + private final UserRepository userRepository; + + @Override + public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) + throws IOException, ServletException { + + HttpServletRequest httpRequest = (HttpServletRequest) request; + HttpServletResponse httpResponse = (HttpServletResponse) response; + + if (((HttpServletRequest) request).getRequestURI().equals("/user")) { + filterChain.doFilter(request, response); + return; + } + + String authHeader = httpRequest.getHeader("Authorization"); + + if (authHeader == null || !authHeader.startsWith(prefix)) { + httpResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Token JWT ausente ou malformado"); + return; + } + + String token = authHeader.substring(prefix.length()); // Remova o prefixo "Bearer " + + try { + Claims claims = Jwts.parser() + .setSigningKey(secret) + .parseClaimsJws(token) + .getBody(); + httpRequest.setAttribute("claims", claims); + + String username = claims.getSubject(); + User user = userRepository.findByEmail(username); + UsernamePasswordAuthenticationToken authToken = new UsernamePasswordAuthenticationToken(user, null); + authToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(httpRequest)); + SecurityContextHolder.getContext().setAuthentication(authToken); + + + + } catch (Exception e) { + httpResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Token JWT inválido ou expirado"); + return; + } + + filterChain.doFilter(request, response); + } + + + @Override + public void destroy() { + } +} \ No newline at end of file diff --git a/src/main/java/com/health/app/repository/UserRepository.java b/src/main/java/com/health/app/repository/UserRepository.java index 6235399..533d53f 100644 --- a/src/main/java/com/health/app/repository/UserRepository.java +++ b/src/main/java/com/health/app/repository/UserRepository.java @@ -6,4 +6,6 @@ public interface UserRepository extends JpaRepository { User save(User user); + + User findByEmail(String email); } diff --git a/src/main/java/com/health/app/services/UserService.java b/src/main/java/com/health/app/services/UserService.java index c10e854..2a9f30e 100644 --- a/src/main/java/com/health/app/services/UserService.java +++ b/src/main/java/com/health/app/services/UserService.java @@ -3,6 +3,7 @@ import com.health.app.dto.CreateUserRequestDTO; import com.health.app.entity.User; import com.health.app.repository.UserRepository; +import com.health.app.util.JwtUtil; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -19,7 +20,7 @@ public User save(CreateUserRequestDTO createUserRequestDTO) { user.setName(createUserRequestDTO.getName()); user.setEmail(createUserRequestDTO.getEmail()); user.setPassword(createUserRequestDTO.getPassword()); - + System.out.println(new JwtUtil().generateToken(user.getEmail())); userRepository.save(user); return user; } diff --git a/src/main/java/com/health/app/util/JwtUtil.java b/src/main/java/com/health/app/util/JwtUtil.java new file mode 100644 index 0000000..3e18c3a --- /dev/null +++ b/src/main/java/com/health/app/util/JwtUtil.java @@ -0,0 +1,32 @@ +package com.health.app.util; + +import io.jsonwebtoken.Jwts; +import io.jsonwebtoken.SignatureAlgorithm; +import java.util.Date; + + +public class JwtUtil { + private String secret = "secreto"; + + public String generateToken(String username) { + return Jwts.builder() + .setSubject(username) + .setIssuedAt(new Date()) + .setExpiration(new Date(System.currentTimeMillis() + 86400000)) // 1 dia de expiração + .signWith(SignatureAlgorithm.HS256, secret) + .compact(); + } + + public Boolean validateToken(String token, String username) { + final String extractedUsername = extractUsername(token); + return (extractedUsername.equals(username) && !isTokenExpired(token)); + } + + private String extractUsername(String token) { + return Jwts.parser().setSigningKey(secret).parseClaimsJws(token).getBody().getSubject(); + } + + private Boolean isTokenExpired(String token) { + return Jwts.parser().setSigningKey(secret).parseClaimsJws(token).getBody().getExpiration().before(new Date()); + } +} \ No newline at end of file