Invalidate auth tokens
This commit is contained in:
@@ -14,6 +14,7 @@ import com.petshop.backend.repository.EmployeeStoreRepository;
|
||||
import com.petshop.backend.repository.UserRepository;
|
||||
import com.petshop.backend.security.JwtUtil;
|
||||
import com.petshop.backend.service.UserBusinessLinkageService;
|
||||
import com.petshop.backend.util.AuthenticationHelper;
|
||||
import jakarta.validation.Valid;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
@@ -22,8 +23,6 @@ import org.springframework.security.authentication.BadCredentialsException;
|
||||
import org.springframework.security.authentication.DisabledException;
|
||||
import org.springframework.security.authentication.InternalAuthenticationServiceException;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
@@ -137,11 +136,7 @@ public class AuthController {
|
||||
|
||||
@GetMapping("/me")
|
||||
public ResponseEntity<UserInfoResponse> getCurrentUser() {
|
||||
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
|
||||
String username = authentication.getName();
|
||||
|
||||
User user = userRepository.findByUsername(username)
|
||||
.orElseThrow(() -> new UsernameNotFoundException("User not found"));
|
||||
User user = getAuthenticatedUser();
|
||||
|
||||
EmployeeStore employeeStore = resolveEmployeeStore(user);
|
||||
|
||||
@@ -159,11 +154,8 @@ public class AuthController {
|
||||
|
||||
@PutMapping("/me")
|
||||
public ResponseEntity<?> updateProfile(@Valid @RequestBody ProfileUpdateRequest request) {
|
||||
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
|
||||
String username = authentication.getName();
|
||||
|
||||
User user = userRepository.findByUsername(username)
|
||||
.orElseThrow(() -> new UsernameNotFoundException("User not found"));
|
||||
User user = getAuthenticatedUser();
|
||||
boolean invalidateToken = false;
|
||||
|
||||
if (request.getUsername() != null && !request.getUsername().equals(user.getUsername())) {
|
||||
if (userRepository.findByUsername(request.getUsername()).isPresent()) {
|
||||
@@ -172,6 +164,7 @@ public class AuthController {
|
||||
return ResponseEntity.status(HttpStatus.CONFLICT).body(error);
|
||||
}
|
||||
user.setUsername(request.getUsername());
|
||||
invalidateToken = true;
|
||||
}
|
||||
|
||||
if (request.getEmail() != null && !request.getEmail().equals(user.getEmail())) {
|
||||
@@ -189,6 +182,11 @@ public class AuthController {
|
||||
|
||||
if (request.getPassword() != null && !request.getPassword().isEmpty()) {
|
||||
user.setPassword(passwordEncoder.encode(request.getPassword()));
|
||||
invalidateToken = true;
|
||||
}
|
||||
|
||||
if (invalidateToken) {
|
||||
user.setTokenVersion(user.getTokenVersion() + 1);
|
||||
}
|
||||
|
||||
User updatedUser = userRepository.save(user);
|
||||
@@ -219,11 +217,7 @@ public class AuthController {
|
||||
|
||||
@PostMapping("/me/avatar")
|
||||
public ResponseEntity<?> uploadAvatar(@RequestParam("avatar") MultipartFile file) {
|
||||
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
|
||||
String username = authentication.getName();
|
||||
|
||||
User user = userRepository.findByUsername(username)
|
||||
.orElseThrow(() -> new UsernameNotFoundException("User not found"));
|
||||
User user = getAuthenticatedUser();
|
||||
|
||||
if (file.isEmpty()) {
|
||||
Map<String, String> error = new HashMap<>();
|
||||
@@ -275,11 +269,7 @@ public class AuthController {
|
||||
|
||||
@GetMapping("/me/avatar")
|
||||
public ResponseEntity<?> getAvatar() {
|
||||
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
|
||||
String username = authentication.getName();
|
||||
|
||||
User user = userRepository.findByUsername(username)
|
||||
.orElseThrow(() -> new UsernameNotFoundException("User not found"));
|
||||
User user = getAuthenticatedUser();
|
||||
|
||||
if (user.getAvatarUrl() == null || user.getAvatarUrl().isEmpty()) {
|
||||
Map<String, String> error = new HashMap<>();
|
||||
@@ -294,11 +284,7 @@ public class AuthController {
|
||||
|
||||
@DeleteMapping("/me/avatar")
|
||||
public ResponseEntity<?> deleteAvatar() {
|
||||
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
|
||||
String username = authentication.getName();
|
||||
|
||||
User user = userRepository.findByUsername(username)
|
||||
.orElseThrow(() -> new UsernameNotFoundException("User not found"));
|
||||
User user = getAuthenticatedUser();
|
||||
|
||||
if (user.getAvatarUrl() != null && !user.getAvatarUrl().isEmpty()) {
|
||||
try {
|
||||
@@ -322,4 +308,12 @@ public class AuthController {
|
||||
response.put("note", "Token remains valid until expiration. Clear token from client storage.");
|
||||
return ResponseEntity.ok(response);
|
||||
}
|
||||
|
||||
private User getAuthenticatedUser() {
|
||||
try {
|
||||
return AuthenticationHelper.getAuthenticatedUser(userRepository);
|
||||
} catch (RuntimeException ex) {
|
||||
throw new UsernameNotFoundException(ex.getMessage(), ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,12 +9,11 @@ import com.petshop.backend.repository.CustomerRepository;
|
||||
import com.petshop.backend.repository.UserRepository;
|
||||
import com.petshop.backend.service.ChatRealtimeService;
|
||||
import com.petshop.backend.service.ChatService;
|
||||
import com.petshop.backend.util.AuthenticationHelper;
|
||||
import jakarta.validation.Valid;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
@@ -37,9 +36,11 @@ public class ChatController {
|
||||
}
|
||||
|
||||
private User getCurrentUser() {
|
||||
UserDetails userDetails = (UserDetails) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
|
||||
return userRepository.findByUsername(userDetails.getUsername())
|
||||
.orElseThrow(() -> new UsernameNotFoundException("User not found"));
|
||||
try {
|
||||
return AuthenticationHelper.getAuthenticatedUser(userRepository);
|
||||
} catch (RuntimeException ex) {
|
||||
throw new UsernameNotFoundException(ex.getMessage(), ex);
|
||||
}
|
||||
}
|
||||
|
||||
@PostMapping("/conversations")
|
||||
|
||||
@@ -68,14 +68,23 @@ public class UserService {
|
||||
User user = userRepository.findById(id)
|
||||
.orElseThrow(() -> new ResourceNotFoundException("User not found with id: " + id));
|
||||
|
||||
boolean invalidateToken =
|
||||
!user.getUsername().equals(request.getUsername())
|
||||
|| user.getRole() != request.getRole()
|
||||
|| !user.getActive().equals(request.getActive() != null ? request.getActive() : true);
|
||||
|
||||
user.setUsername(request.getUsername());
|
||||
if (request.getPassword() != null && !request.getPassword().trim().isEmpty()) {
|
||||
user.setPassword(passwordEncoder.encode(request.getPassword()));
|
||||
invalidateToken = true;
|
||||
}
|
||||
user.setFullName(request.getFullName());
|
||||
user.setEmail(request.getEmail());
|
||||
user.setRole(request.getRole());
|
||||
user.setActive(request.getActive() != null ? request.getActive() : true);
|
||||
if (invalidateToken) {
|
||||
user.setTokenVersion(user.getTokenVersion() + 1);
|
||||
}
|
||||
|
||||
user = userRepository.save(user);
|
||||
return mapToResponse(user);
|
||||
|
||||
@@ -6,6 +6,7 @@ import com.petshop.backend.entity.User;
|
||||
import com.petshop.backend.repository.CustomerRepository;
|
||||
import com.petshop.backend.repository.EmployeeRepository;
|
||||
import com.petshop.backend.repository.UserRepository;
|
||||
import com.petshop.backend.security.AppPrincipal;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.stereotype.Component;
|
||||
@@ -13,11 +14,34 @@ import org.springframework.stereotype.Component;
|
||||
@Component
|
||||
public class AuthenticationHelper {
|
||||
|
||||
public static User getAuthenticatedUser(UserRepository userRepository) {
|
||||
public static Authentication getAuthentication() {
|
||||
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
|
||||
if (authentication == null || !authentication.isAuthenticated()) {
|
||||
throw new RuntimeException("No authenticated user found");
|
||||
}
|
||||
return authentication;
|
||||
}
|
||||
|
||||
public static AppPrincipal getAuthenticatedPrincipal() {
|
||||
Object principal = getAuthentication().getPrincipal();
|
||||
if (principal instanceof AppPrincipal appPrincipal) {
|
||||
return appPrincipal;
|
||||
}
|
||||
throw new RuntimeException("Authenticated principal is not supported");
|
||||
}
|
||||
|
||||
public static Long getAuthenticatedUserId() {
|
||||
return getAuthenticatedPrincipal().getUserId();
|
||||
}
|
||||
|
||||
public static User getAuthenticatedUser(UserRepository userRepository) {
|
||||
Authentication authentication = getAuthentication();
|
||||
Object principal = authentication.getPrincipal();
|
||||
|
||||
if (principal instanceof AppPrincipal appPrincipal) {
|
||||
return userRepository.findById(appPrincipal.getUserId())
|
||||
.orElseThrow(() -> new RuntimeException("User not found: " + appPrincipal.getUserId()));
|
||||
}
|
||||
|
||||
String username = authentication.getName();
|
||||
return userRepository.findByUsername(username)
|
||||
|
||||
Reference in New Issue
Block a user