diff --git a/pom.xml b/pom.xml index 89d0a60..49ac77e 100644 --- a/pom.xml +++ b/pom.xml @@ -64,10 +64,9 @@ 0.11.5 - org.projectlombok - lombok - 1.18.20 - provided + jakarta.validation + jakarta.validation-api + 2.0.2 diff --git a/src/main/java/com/faf223/expensetrackerfaf/config/SecurityConfiguration.java b/src/main/java/com/faf223/expensetrackerfaf/config/SecurityConfiguration.java index b494885..430f3ff 100644 --- a/src/main/java/com/faf223/expensetrackerfaf/config/SecurityConfiguration.java +++ b/src/main/java/com/faf223/expensetrackerfaf/config/SecurityConfiguration.java @@ -4,7 +4,7 @@ import lombok.RequiredArgsConstructor; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.authentication.AuthenticationProvider; -import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; +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.http.SessionCreationPolicy; @@ -14,7 +14,7 @@ import org.springframework.security.web.authentication.UsernamePasswordAuthentic @Configuration @EnableWebSecurity @RequiredArgsConstructor -@EnableGlobalMethodSecurity(prePostEnabled = true) +@EnableMethodSecurity public class SecurityConfiguration { private final JwtAuthenticationFilter jwtAuthFilter; diff --git a/src/main/java/com/faf223/expensetrackerfaf/controller/auth/AuthenticationController.java b/src/main/java/com/faf223/expensetrackerfaf/controller/auth/AuthenticationController.java index 1f375ea..43c25df 100644 --- a/src/main/java/com/faf223/expensetrackerfaf/controller/auth/AuthenticationController.java +++ b/src/main/java/com/faf223/expensetrackerfaf/controller/auth/AuthenticationController.java @@ -23,4 +23,9 @@ public class AuthenticationController { public ResponseEntity authenticate(@RequestBody AuthenticationRequest request) { return ResponseEntity.ok(service.authenticate(request)); } + + @PostMapping("/refresh") + public ResponseEntity refreshAccessToken(@RequestBody TokenRefreshRequest refreshRequest) { + return ResponseEntity.ok(service.refreshAccessToken(refreshRequest)); + } } diff --git a/src/main/java/com/faf223/expensetrackerfaf/controller/auth/AuthenticationResponse.java b/src/main/java/com/faf223/expensetrackerfaf/controller/auth/AuthenticationResponse.java index bc92552..b182217 100644 --- a/src/main/java/com/faf223/expensetrackerfaf/controller/auth/AuthenticationResponse.java +++ b/src/main/java/com/faf223/expensetrackerfaf/controller/auth/AuthenticationResponse.java @@ -1,5 +1,6 @@ package com.faf223.expensetrackerfaf.controller.auth; +import com.fasterxml.jackson.annotation.JsonProperty; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; @@ -11,5 +12,8 @@ import lombok.NoArgsConstructor; @NoArgsConstructor public class AuthenticationResponse { - private String token; + @JsonProperty("access_token") + private String accessToken; + @JsonProperty("refresh_token") + private String refreshToken; } diff --git a/src/main/java/com/faf223/expensetrackerfaf/controller/auth/TokenRefreshRequest.java b/src/main/java/com/faf223/expensetrackerfaf/controller/auth/TokenRefreshRequest.java new file mode 100644 index 0000000..bffe531 --- /dev/null +++ b/src/main/java/com/faf223/expensetrackerfaf/controller/auth/TokenRefreshRequest.java @@ -0,0 +1,8 @@ +package com.faf223.expensetrackerfaf.controller.auth; + +import lombok.Data; + +@Data +public class TokenRefreshRequest { + private String refreshToken; +} diff --git a/src/main/java/com/faf223/expensetrackerfaf/repository/UserRepository.java b/src/main/java/com/faf223/expensetrackerfaf/repository/UserRepository.java index d370b0a..e044309 100644 --- a/src/main/java/com/faf223/expensetrackerfaf/repository/UserRepository.java +++ b/src/main/java/com/faf223/expensetrackerfaf/repository/UserRepository.java @@ -7,4 +7,6 @@ import java.util.Optional; public interface UserRepository extends JpaRepository { Optional getUserByUserUuid(String userUuid); + + Optional findByUsername(String username); } diff --git a/src/main/java/com/faf223/expensetrackerfaf/service/AuthenticationService.java b/src/main/java/com/faf223/expensetrackerfaf/service/AuthenticationService.java index 96cb4a4..bbc0440 100644 --- a/src/main/java/com/faf223/expensetrackerfaf/service/AuthenticationService.java +++ b/src/main/java/com/faf223/expensetrackerfaf/service/AuthenticationService.java @@ -4,6 +4,7 @@ import com.faf223.expensetrackerfaf.config.JwtService; import com.faf223.expensetrackerfaf.controller.auth.AuthenticationRequest; import com.faf223.expensetrackerfaf.controller.auth.AuthenticationResponse; import com.faf223.expensetrackerfaf.controller.auth.RegisterRequest; +import com.faf223.expensetrackerfaf.controller.auth.TokenRefreshRequest; import com.faf223.expensetrackerfaf.model.Credential; import com.faf223.expensetrackerfaf.model.User; import com.faf223.expensetrackerfaf.repository.CredentialRepository; @@ -12,10 +13,14 @@ import com.faf223.expensetrackerfaf.security.PersonDetails; import lombok.RequiredArgsConstructor; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.stereotype.Service; +import java.io.IOException; +import java.util.Optional; + @Service @RequiredArgsConstructor public class AuthenticationService { @@ -38,9 +43,13 @@ public class AuthenticationService { Credential credential = new Credential(user, request.getEmail(), passwordEncoder.encode(request.getPassword())); credentialRepository.save(credential); - String jwtToken = jwtService.generateToken(new PersonDetails(credential)); + UserDetails userDetails = new PersonDetails(credential); + String jwtToken = jwtService.generateToken(userDetails); + String refreshToken = jwtService.generateToken(userDetails); + return AuthenticationResponse.builder() - .token(jwtToken) + .accessToken(jwtToken) + .refreshToken(refreshToken) .build(); } @@ -49,10 +58,30 @@ public class AuthenticationService { Credential credential = credentialRepository.findByEmail(request.getEmail()).orElseThrow((() -> new UsernameNotFoundException("User not found"))); - String jwtToken = jwtService.generateToken(new PersonDetails(credential)); + UserDetails userDetails = new PersonDetails(credential); + String jwtToken = jwtService.generateToken(userDetails); + String refreshToken = jwtService.generateToken(userDetails); return AuthenticationResponse.builder() - .token(jwtToken) + .accessToken(jwtToken) + .refreshToken(refreshToken) .build(); } + public AuthenticationResponse refreshAccessToken(TokenRefreshRequest refreshRequest) { + String refreshToken = refreshRequest.getRefreshToken(); + + Optional credential = credentialRepository.findByEmail(jwtService.extractUsername(refreshToken)); + if (credential.isPresent()) { + UserDetails userDetails = new PersonDetails(credential.get()); + + String jwtToken = jwtService.generateToken(userDetails); + return AuthenticationResponse.builder() + .accessToken(jwtToken) + .refreshToken(refreshToken) // Return the same refresh token + .build(); + }else { + throw new RuntimeException("Invalid or expired refresh token"); + } + } + }