From 365448b7ee1db475e81cd3041652d29196de37de Mon Sep 17 00:00:00 2001 From: silnov Date: Thu, 7 Sep 2023 11:49:42 +0300 Subject: [PATCH] Refactor refresh token endpoint --- .../auth/AuthenticationController.java | 14 +++----- ...henticationControllerExceptionHandler.java | 23 +++++++++++++ .../security/auth/AuthenticationService.java | 32 +++++++------------ .../exception/InvalidAuthTokenException.java | 7 ++++ .../UserNotFoundForAuthException.java | 7 ++++ 5 files changed, 53 insertions(+), 30 deletions(-) create mode 100644 src/main/java/com/alibou/security/auth/AuthenticationControllerExceptionHandler.java create mode 100644 src/main/java/com/alibou/security/exception/InvalidAuthTokenException.java create mode 100644 src/main/java/com/alibou/security/exception/UserNotFoundForAuthException.java diff --git a/src/main/java/com/alibou/security/auth/AuthenticationController.java b/src/main/java/com/alibou/security/auth/AuthenticationController.java index e1d5107..230c837 100644 --- a/src/main/java/com/alibou/security/auth/AuthenticationController.java +++ b/src/main/java/com/alibou/security/auth/AuthenticationController.java @@ -1,16 +1,13 @@ package com.alibou.security.auth; -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; 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.RequestHeader; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; -import java.io.IOException; - @RestController @RequestMapping("/api/v1/auth") @RequiredArgsConstructor @@ -32,11 +29,10 @@ public ResponseEntity authenticate( } @PostMapping("/refresh-token") - public void refreshToken( - HttpServletRequest request, - HttpServletResponse response - ) throws IOException { - service.refreshToken(request, response); + public AuthenticationResponse refreshToken( + @RequestHeader("Authorization") String refreshToken + ) { + return service.refreshToken(refreshToken); } diff --git a/src/main/java/com/alibou/security/auth/AuthenticationControllerExceptionHandler.java b/src/main/java/com/alibou/security/auth/AuthenticationControllerExceptionHandler.java new file mode 100644 index 0000000..3b27b6b --- /dev/null +++ b/src/main/java/com/alibou/security/auth/AuthenticationControllerExceptionHandler.java @@ -0,0 +1,23 @@ +package com.alibou.security.auth; + +import com.alibou.security.exception.InvalidAuthTokenException; +import com.alibou.security.exception.UserNotFoundForAuthException; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.ControllerAdvice; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.context.request.WebRequest; + +import static org.springframework.http.HttpStatus.UNAUTHORIZED; + +@ControllerAdvice +public class AuthenticationControllerExceptionHandler { + @ExceptionHandler(InvalidAuthTokenException.class) + public ResponseEntity handleInvalidAuthTokenException(InvalidAuthTokenException ex, WebRequest request) { + return ResponseEntity.badRequest().body(ex.getMessage()); + } + + @ExceptionHandler(UserNotFoundForAuthException.class) + public ResponseEntity handleUserNotFoundForAuthException(UserNotFoundForAuthException ex, WebRequest request) { + return ResponseEntity.status(UNAUTHORIZED).body(ex.getMessage()); + } +} diff --git a/src/main/java/com/alibou/security/auth/AuthenticationService.java b/src/main/java/com/alibou/security/auth/AuthenticationService.java index 53193a7..ebf45db 100644 --- a/src/main/java/com/alibou/security/auth/AuthenticationService.java +++ b/src/main/java/com/alibou/security/auth/AuthenticationService.java @@ -1,27 +1,19 @@ package com.alibou.security.auth; import com.alibou.security.config.JwtService; +import com.alibou.security.exception.InvalidAuthTokenException; +import com.alibou.security.exception.UserNotFoundForAuthException; import com.alibou.security.token.Token; import com.alibou.security.token.TokenRepository; import com.alibou.security.token.TokenType; -import com.alibou.security.user.Role; import com.alibou.security.user.User; import com.alibou.security.user.UserRepository; -import com.fasterxml.jackson.databind.ObjectMapper; -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; import lombok.RequiredArgsConstructor; -import org.springframework.http.HttpHeaders; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; -import org.springframework.security.core.context.SecurityContextHolder; -import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.crypto.password.PasswordEncoder; -import org.springframework.security.web.authentication.WebAuthenticationDetailsSource; import org.springframework.stereotype.Service; -import java.io.IOException; - @Service @RequiredArgsConstructor public class AuthenticationService { @@ -90,17 +82,12 @@ private void revokeAllUserTokens(User user) { tokenRepository.saveAll(validUserTokens); } - public void refreshToken( - HttpServletRequest request, - HttpServletResponse response - ) throws IOException { - final String authHeader = request.getHeader(HttpHeaders.AUTHORIZATION); - final String refreshToken; + public AuthenticationResponse refreshToken(String refreshToken) { final String userEmail; - if (authHeader == null ||!authHeader.startsWith("Bearer ")) { - return; + if (refreshToken == null ||!refreshToken.startsWith("Bearer ")) { + throw new InvalidAuthTokenException("Invalid refresh token"); } - refreshToken = authHeader.substring(7); + refreshToken = refreshToken.substring(7); userEmail = jwtService.extractUsername(refreshToken); if (userEmail != null) { var user = this.repository.findByEmail(userEmail) @@ -109,12 +96,15 @@ public void refreshToken( var accessToken = jwtService.generateToken(user); revokeAllUserTokens(user); saveUserToken(user, accessToken); - var authResponse = AuthenticationResponse.builder() + return AuthenticationResponse.builder() .accessToken(accessToken) .refreshToken(refreshToken) .build(); - new ObjectMapper().writeValue(response.getOutputStream(), authResponse); + } else { + throw new InvalidAuthTokenException("Invalid refresh token"); } + } else { + throw new UserNotFoundForAuthException("User for token not found"); } } } diff --git a/src/main/java/com/alibou/security/exception/InvalidAuthTokenException.java b/src/main/java/com/alibou/security/exception/InvalidAuthTokenException.java new file mode 100644 index 0000000..2f86a76 --- /dev/null +++ b/src/main/java/com/alibou/security/exception/InvalidAuthTokenException.java @@ -0,0 +1,7 @@ +package com.alibou.security.exception; + +public class InvalidAuthTokenException extends RuntimeException { + public InvalidAuthTokenException(String message) { + super(message); + } +} diff --git a/src/main/java/com/alibou/security/exception/UserNotFoundForAuthException.java b/src/main/java/com/alibou/security/exception/UserNotFoundForAuthException.java new file mode 100644 index 0000000..fbf3c0e --- /dev/null +++ b/src/main/java/com/alibou/security/exception/UserNotFoundForAuthException.java @@ -0,0 +1,7 @@ +package com.alibou.security.exception; + +public class UserNotFoundForAuthException extends RuntimeException { + public UserNotFoundForAuthException(String message) { + super(message); + } +}