From 251bb3710509890f9bae27e040da744a612c475f Mon Sep 17 00:00:00 2001 From: vladp Date: Wed, 21 Jan 2026 12:21:14 +0700 Subject: [PATCH] fix authService --- .../nocopy/controller/ApiController.java | 3 +- .../nocopy/handler/AuthRequestHandler.java | 2 +- .../nocopy/handler/FileUploadHandler.java | 2 +- .../nocopy/handler/LogoutRequestHandler.java | 6 +- .../handler/VerifyRegisterUserHandler.java | 2 +- .../repository/AuthTokenRepository.java | 1 + .../nocopy/service/auth/AuthService.java | 104 --------------- .../auth/CleanupTokenSessionsService.java | 2 +- .../nocopy/service/register/AuthService.java | 126 ++++++++++++++++++ .../service/user/UserContentService.java | 72 ---------- .../soune/nocopy/service/AuthServiceTest.java | 102 -------------- 11 files changed, 135 insertions(+), 287 deletions(-) delete mode 100644 src/main/java/ru/soune/nocopy/service/auth/AuthService.java delete mode 100644 src/main/java/ru/soune/nocopy/service/user/UserContentService.java delete mode 100644 src/test/java/ru/soune/nocopy/service/AuthServiceTest.java diff --git a/src/main/java/ru/soune/nocopy/controller/ApiController.java b/src/main/java/ru/soune/nocopy/controller/ApiController.java index ca16d18..371a750 100644 --- a/src/main/java/ru/soune/nocopy/controller/ApiController.java +++ b/src/main/java/ru/soune/nocopy/controller/ApiController.java @@ -19,12 +19,11 @@ import ru.soune.nocopy.dto.file.ChunkUploadResponse; import ru.soune.nocopy.dto.file.CompleteUploadResponse; import ru.soune.nocopy.dto.file.FileEntityResponse; import ru.soune.nocopy.dto.file.UploadProgress; -import ru.soune.nocopy.entity.user.AuthToken; import ru.soune.nocopy.entity.file.FileStatus; import ru.soune.nocopy.entity.file.UploadStatus; import ru.soune.nocopy.exception.*; import ru.soune.nocopy.handler.*; -import ru.soune.nocopy.service.auth.AuthService; +import ru.soune.nocopy.service.register.AuthService; import ru.soune.nocopy.service.file.FileEntityService; import ru.soune.nocopy.service.file.FileUploadService; diff --git a/src/main/java/ru/soune/nocopy/handler/AuthRequestHandler.java b/src/main/java/ru/soune/nocopy/handler/AuthRequestHandler.java index c79ec06..aca3926 100644 --- a/src/main/java/ru/soune/nocopy/handler/AuthRequestHandler.java +++ b/src/main/java/ru/soune/nocopy/handler/AuthRequestHandler.java @@ -9,7 +9,7 @@ import ru.soune.nocopy.dto.BaseResponse; import ru.soune.nocopy.dto.MessageCode; import ru.soune.nocopy.dto.TokenProcessRequest; import ru.soune.nocopy.exception.NotFoundAuthToken; -import ru.soune.nocopy.service.auth.AuthService; +import ru.soune.nocopy.service.register.AuthService; import java.util.Map; diff --git a/src/main/java/ru/soune/nocopy/handler/FileUploadHandler.java b/src/main/java/ru/soune/nocopy/handler/FileUploadHandler.java index 193f01b..c4ae60a 100644 --- a/src/main/java/ru/soune/nocopy/handler/FileUploadHandler.java +++ b/src/main/java/ru/soune/nocopy/handler/FileUploadHandler.java @@ -17,7 +17,7 @@ import ru.soune.nocopy.exception.*; import ru.soune.nocopy.handler.validator.FileUploadRequestValidator; import ru.soune.nocopy.repository.AuthTokenRepository; import ru.soune.nocopy.repository.FileUploadSessionRepository; -import ru.soune.nocopy.service.auth.AuthService; +import ru.soune.nocopy.service.register.AuthService; import ru.soune.nocopy.service.file.FileUploadService; import java.util.*; diff --git a/src/main/java/ru/soune/nocopy/handler/LogoutRequestHandler.java b/src/main/java/ru/soune/nocopy/handler/LogoutRequestHandler.java index 4fa77b1..3216d16 100644 --- a/src/main/java/ru/soune/nocopy/handler/LogoutRequestHandler.java +++ b/src/main/java/ru/soune/nocopy/handler/LogoutRequestHandler.java @@ -33,16 +33,16 @@ public class LogoutRequestHandler implements RequestHandler { LogoutRequest logoutRequest = objectMapper.convertValue(request.getMessageBody(), LogoutRequest.class); Optional opToken = authTokenRepository.findByToken(logoutRequest.getToken()); - Optional user = userRepository.findByEmail(logoutRequest.getEmail()); + User user = userRepository.findByEmail(logoutRequest.getEmail()); - if (opToken.isEmpty() || user.isEmpty()) { + if (opToken.isEmpty() || user == null) { throw new NotValidFieldException("User with email or token not found", new BaseResponse(request.getMsgId(), MessageCode.AUTH_EMAIL_OR_TOKEN_NOT_FOUND.getCode(), MessageCode.AUTH_EMAIL_OR_TOKEN_NOT_FOUND.getDescription(), new LogoutRequest(logoutRequest.getEmail(), logoutRequest.getToken()))); } - if (!Objects.equals(opToken.get().getUser().getId(), user.get().getId())) { + if (!Objects.equals(opToken.get().getUser().getId(), user.getId())) { throw new NotValidFieldException("User token mismatch with user", new BaseResponse(request.getMsgId(), MessageCode.AUTH_TOKEN_MISMATCH.getCode(), MessageCode.AUTH_TOKEN_MISMATCH.getDescription(), diff --git a/src/main/java/ru/soune/nocopy/handler/VerifyRegisterUserHandler.java b/src/main/java/ru/soune/nocopy/handler/VerifyRegisterUserHandler.java index 50f2dc0..00a1e10 100644 --- a/src/main/java/ru/soune/nocopy/handler/VerifyRegisterUserHandler.java +++ b/src/main/java/ru/soune/nocopy/handler/VerifyRegisterUserHandler.java @@ -51,7 +51,7 @@ public class VerifyRegisterUserHandler implements RequestHandler { User user = userRepository.findById(userId) .orElseThrow(() -> new UserNotFoundException("User not found with id: " + userId)); - Optional userAuthTokens = authTokenRepository.findByUserIdAndIsActive(userId, false); + Optional userAuthTokens = authTokenRepository.findByUserId(userId); AuthToken authToken = userAuthTokens.isEmpty() ? authService.generateAuthToken(user): userAuthTokens.get(); diff --git a/src/main/java/ru/soune/nocopy/repository/AuthTokenRepository.java b/src/main/java/ru/soune/nocopy/repository/AuthTokenRepository.java index 9dbc08e..08b2ee5 100644 --- a/src/main/java/ru/soune/nocopy/repository/AuthTokenRepository.java +++ b/src/main/java/ru/soune/nocopy/repository/AuthTokenRepository.java @@ -14,4 +14,5 @@ public interface AuthTokenRepository extends JpaRepository { Optional findByLastUsedAtBefore(LocalDateTime lastUsedAt); Optional findByToken(String token); Optional findByUserIdAndIsActive(Long userId, boolean isActive); + Optional findByUserId(Long userId); } diff --git a/src/main/java/ru/soune/nocopy/service/auth/AuthService.java b/src/main/java/ru/soune/nocopy/service/auth/AuthService.java deleted file mode 100644 index e8d3259..0000000 --- a/src/main/java/ru/soune/nocopy/service/auth/AuthService.java +++ /dev/null @@ -1,104 +0,0 @@ -package ru.soune.nocopy.service.register; - -import lombok.RequiredArgsConstructor; -import org.springframework.context.MessageSource; -import org.springframework.security.crypto.password.PasswordEncoder; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; -import ru.soune.nocopy.dto.*; -import ru.soune.nocopy.dto.register.LoginAnswer; -import ru.soune.nocopy.dto.register.LoginRequest; -import ru.soune.nocopy.dto.register.RegRequest; -import ru.soune.nocopy.entity.user.AuthToken; -import ru.soune.nocopy.entity.user.User; -import ru.soune.nocopy.exception.NotValidFieldException; -import ru.soune.nocopy.repository.AuthTokenRepository; -import ru.soune.nocopy.repository.UserRepository; - -import java.security.SecureRandom; -import java.time.LocalDateTime; -import java.util.*; - -@Service -@RequiredArgsConstructor -public class AuthService { - - private final UserRepository userRepository; - - private final AuthTokenRepository authTokenRepository; - - private final PasswordEncoder passwordEncoder; - - private final MessageSource messageSource; - - private final SecureRandom secureRandom = new SecureRandom(); - - @Transactional - public AuthToken register(RegRequest registerRequest) { - User user = new User(); - user.setFullName(registerRequest.getFullName()); - user.setEmail(registerRequest.getEmail()); - user.setPassword(passwordEncoder.encode(registerRequest.getPassword())); - - if (registerRequest.getCompanyName() != null) { - user.setCompany(registerRequest.getCompanyName()); - } - - if (registerRequest.getPhone() != null) { - user.setPhone(registerRequest.getPhone()); - } - - User savedUser = userRepository.save(user); - - AuthToken authToken = genereateAuthToken(savedUser); - - return authTokenRepository.save(authToken); - } - - @Transactional - public AuthToken login(LoginRequest request) { - User user = userRepository.findByEmail(request.getEmail()); - - if (!passwordEncoder.matches(request.getPassword(), user.getPassword())) { - LoginAnswer loginAnswer = new LoginAnswer(); - loginAnswer.setFieldErrors(Arrays.asList(Map.of("password", request.getPassword()))); - - throw new NotValidFieldException("Invalid password", new BaseResponse(20003, - MessageCode.AUTH_PASSWORD_NOT_MATCHES.getCode(), - MessageCode.AUTH_PASSWORD_NOT_MATCHES.getDescription(), loginAnswer)); - } - - user.setLastLoginAt(LocalDateTime.now()); - User savedUser = userRepository.save(user); - - AuthToken authToken = new AuthToken(); - authToken.setToken(generateAuthToken()); - authToken.setUser(savedUser); - - return authTokenRepository.save(authToken); - } - - @Transactional - public void logout(String token) { - authTokenRepository.findByToken(token) - .ifPresent(authTokenRepository::delete); - } - - public AuthToken generateAuthToken(User user) { - return authTokenRepository.save(genereateAuthToken(user)); - } - - private AuthToken genereateAuthToken(User user) { - AuthToken authToken = new AuthToken(); - authToken.setToken(generateAuthToken()); - authToken.setUser(user); - - return authToken; - } - - private String generateAuthToken() { - byte[] bytes = new byte[32]; - secureRandom.nextBytes(bytes); - return Base64.getUrlEncoder().withoutPadding().encodeToString(bytes); - } -} diff --git a/src/main/java/ru/soune/nocopy/service/auth/CleanupTokenSessionsService.java b/src/main/java/ru/soune/nocopy/service/auth/CleanupTokenSessionsService.java index 5ac5128..9d7045b 100644 --- a/src/main/java/ru/soune/nocopy/service/auth/CleanupTokenSessionsService.java +++ b/src/main/java/ru/soune/nocopy/service/auth/CleanupTokenSessionsService.java @@ -7,7 +7,7 @@ import org.springframework.beans.factory.annotation.Value; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional; -import ru.soune.nocopy.entity.AuthToken; +import ru.soune.nocopy.entity.user.AuthToken; import ru.soune.nocopy.repository.AuthTokenRepository; import java.time.LocalDateTime; diff --git a/src/main/java/ru/soune/nocopy/service/register/AuthService.java b/src/main/java/ru/soune/nocopy/service/register/AuthService.java index e69de29..1038e63 100644 --- a/src/main/java/ru/soune/nocopy/service/register/AuthService.java +++ b/src/main/java/ru/soune/nocopy/service/register/AuthService.java @@ -0,0 +1,126 @@ +package ru.soune.nocopy.service.register; + +import lombok.RequiredArgsConstructor; +import org.springframework.context.MessageSource; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import ru.soune.nocopy.dto.*; +import ru.soune.nocopy.dto.register.LoginAnswer; +import ru.soune.nocopy.dto.register.LoginRequest; +import ru.soune.nocopy.dto.register.RegRequest; +import ru.soune.nocopy.entity.user.AuthToken; +import ru.soune.nocopy.entity.user.User; +import ru.soune.nocopy.exception.NotFoundAuthToken; +import ru.soune.nocopy.exception.NotValidFieldException; +import ru.soune.nocopy.repository.AuthTokenRepository; +import ru.soune.nocopy.repository.UserRepository; + +import java.security.SecureRandom; +import java.time.LocalDateTime; +import java.util.*; + +@Service +@RequiredArgsConstructor +public class AuthService { + + private final UserRepository userRepository; + + private final AuthTokenRepository authTokenRepository; + + private final PasswordEncoder passwordEncoder; + + private final MessageSource messageSource; + + private final SecureRandom secureRandom = new SecureRandom(); + + @Transactional + public AuthToken register(RegRequest registerRequest) { + User user = new User(); + user.setFullName(registerRequest.getFullName()); + user.setEmail(registerRequest.getEmail()); + user.setPassword(passwordEncoder.encode(registerRequest.getPassword())); + + if (registerRequest.getCompanyName() != null) { + user.setCompany(registerRequest.getCompanyName()); + } + + if (registerRequest.getPhone() != null) { + user.setPhone(registerRequest.getPhone()); + } + + User savedUser = userRepository.save(user); + + AuthToken authToken = genereateAuthToken(savedUser); + + return authTokenRepository.save(authToken); + } + + @Transactional + public Long useUserAuthToken(String token) { + if (token == null || token.isBlank()) { + throw new NotFoundAuthToken("Token is required"); + } + + if (token.startsWith("Bearer ")) { + token = token.replace("Bearer ", ""); + } + + AuthToken authToken = authTokenRepository.findByToken(token) + .orElseThrow(() -> new NotFoundAuthToken("Token not found")); + authToken.setLastUsedAt(LocalDateTime.now()); + authToken.setExpiresAt(LocalDateTime.now().plusHours(1)); + + authTokenRepository.save(authToken); + + return authToken.getUser().getId(); + } + + + @Transactional + public AuthToken login(LoginRequest request) { + User user = userRepository.findByEmail(request.getEmail()); + + if (!passwordEncoder.matches(request.getPassword(), user.getPassword())) { + LoginAnswer loginAnswer = new LoginAnswer(); + loginAnswer.setFieldErrors(Arrays.asList(Map.of("password", request.getPassword()))); + + throw new NotValidFieldException("Invalid password", new BaseResponse(20003, + MessageCode.AUTH_PASSWORD_NOT_MATCHES.getCode(), + MessageCode.AUTH_PASSWORD_NOT_MATCHES.getDescription(), loginAnswer)); + } + + user.setLastLoginAt(LocalDateTime.now()); + User savedUser = userRepository.save(user); + + AuthToken authToken = new AuthToken(); + authToken.setToken(generateAuthToken()); + authToken.setUser(savedUser); + + return authTokenRepository.save(authToken); + } + + @Transactional + public void logout(String token) { + authTokenRepository.findByToken(token) + .ifPresent(authTokenRepository::delete); + } + + public AuthToken generateAuthToken(User user) { + return authTokenRepository.save(genereateAuthToken(user)); + } + + private AuthToken genereateAuthToken(User user) { + AuthToken authToken = new AuthToken(); + authToken.setToken(generateAuthToken()); + authToken.setUser(user); + + return authToken; + } + + private String generateAuthToken() { + byte[] bytes = new byte[32]; + secureRandom.nextBytes(bytes); + return Base64.getUrlEncoder().withoutPadding().encodeToString(bytes); + } +} diff --git a/src/main/java/ru/soune/nocopy/service/user/UserContentService.java b/src/main/java/ru/soune/nocopy/service/user/UserContentService.java deleted file mode 100644 index 63510e8..0000000 --- a/src/main/java/ru/soune/nocopy/service/user/UserContentService.java +++ /dev/null @@ -1,72 +0,0 @@ -package ru.soune.nocopy.service.user; - -import lombok.AllArgsConstructor; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; -import ru.soune.nocopy.dto.user.UserContentRequest; -import ru.soune.nocopy.dto.user.UserContentUpdateRequest; -import ru.soune.nocopy.entity.file.FileType; -import ru.soune.nocopy.entity.user.User; -import ru.soune.nocopy.entity.user.UserContent; -import ru.soune.nocopy.exception.ContentNotFoundException; -import ru.soune.nocopy.exception.UserNotFoundException; -import ru.soune.nocopy.mapper.UserContentMapper; -import ru.soune.nocopy.repository.UserContentRepository; -import ru.soune.nocopy.repository.UserRepository; - -import java.util.List; -import java.util.Optional; - -@Service -@AllArgsConstructor -public class UserContentService { - - private final UserContentRepository userContentRepository; - - private final UserRepository userRepository; - - private final UserContentMapper userContentMapper; - - public List findByUser(long userId) { - return userContentRepository.findByUserId(userId); - } - - @Transactional - public UserContent addUserContent(UserContentRequest userContentRequest) { - UserContent userContent = new UserContent(); - - Optional byEmail = userRepository.findByEmail(userContentRequest.userEmail()); - User user = byEmail.orElseThrow(() -> new UserNotFoundException(userContentRequest.userEmail())); - - userContent.setUser(user); - userContent.setFilename(userContentRequest.fileName()); - userContent.setFileExtension(userContentRequest.fileExtension()); - userContent.setFilePath(userContentRequest.filePath()); - userContent.setFileType(FileType.valueOf(userContentRequest.fileType())); - userContent.setOriginalFilename(userContentRequest.originalFilename()); - userContent.setProtectionLevel(userContentRequest.protectionLevel()); - userContent.setFileSize(userContentRequest.fileSize()); - - //TODO add - // @Column(name = "protection_hash", length = 64) - // private String protectionHash; - // @Column(name = "watermark_id", length = 50) - // private String watermarkId; - - return userContentRepository.save(userContent); - } - - @Transactional - public UserContent updateUserContent(UserContentUpdateRequest userContentRequest) { - UserContent entity = userContentRepository.findById(userContentRequest.id()) - .orElseThrow(() -> new ContentNotFoundException("Content not found with: " + userContentRequest.id())); - - userContentMapper.updateEntityFromDto(userContentRequest, entity); - - return userContentRepository.save(entity); - } - - public void deleteUserContent(long userContentId) { - userContentRepository.deleteById(userContentId); - } -} diff --git a/src/test/java/ru/soune/nocopy/service/AuthServiceTest.java b/src/test/java/ru/soune/nocopy/service/AuthServiceTest.java deleted file mode 100644 index 574ab25..0000000 --- a/src/test/java/ru/soune/nocopy/service/AuthServiceTest.java +++ /dev/null @@ -1,102 +0,0 @@ -package ru.soune.nocopy.service; - -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.mockito.ArgumentCaptor; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; -import org.springframework.context.MessageSource; -import org.springframework.security.crypto.password.PasswordEncoder; -import ru.soune.nocopy.dto.register.LoginRequest; -import ru.soune.nocopy.entity.user.AuthToken; -import ru.soune.nocopy.entity.user.User; -import ru.soune.nocopy.exception.NotValidationPasswordException; -import ru.soune.nocopy.exception.UserNotFoundException; -import ru.soune.nocopy.repository.AuthTokenRepository; -import ru.soune.nocopy.repository.UserRepository; -import ru.soune.nocopy.service.register.AuthService; - -import java.util.Optional; - -import static org.junit.jupiter.api.Assertions.*; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -public class AuthServiceTest { - - @Mock - private UserRepository userRepository; - - @Mock - private AuthTokenRepository authTokenRepository; - - @Mock - private PasswordEncoder passwordEncoder; - - @Mock - private MessageSource messageSource; - - @InjectMocks - private AuthService authService; - - @BeforeEach - void setUp() { - MockitoAnnotations.openMocks(this); - } - - @Test - void login_success() { - LoginRequest request = new LoginRequest("test@mail.com", "password"); - - User user = new User(); - user.setId(1L); - user.setEmail("test@mail.com"); - user.setPassword("encoded_pass"); - - when(userRepository.findByEmail("test@mail.com")) - .thenReturn(Optional.of(user)); - when(passwordEncoder.matches("password", "encoded_pass")) - .thenReturn(true); - when(authTokenRepository.save(any(AuthToken.class))) - .thenAnswer(invocation -> invocation.getArgument(0)); - - AuthToken token = authService.login(request); - - assertNotNull(token); - assertNotNull(token.getToken()); -// assertEquals(user.getTokens().get(0), token.getUser()); - - ArgumentCaptor captor = ArgumentCaptor.forClass(AuthToken.class); - verify(authTokenRepository).save(captor.capture()); - -// assertEquals(user, captor.getValue().getUser()); - assertNotNull(captor.getValue().getToken()); - } - - - @Test - void login_userNotFound() { - LoginRequest request = new LoginRequest("missing@mail.com", "pwd"); - - when(userRepository.findByEmail("missing@mail.com")).thenReturn(Optional.empty()); - - assertThrows(UserNotFoundException.class, () -> authService.login(request)); - } - - - @Test - void login_invalidPassword() { - LoginRequest request = new LoginRequest("test@mail.com", "wrong"); - - User user = new User(); - user.setEmail("test@mail.com"); - user.setPassword("encoded_pass"); - - when(userRepository.findByEmail("test@mail.com")).thenReturn(Optional.of(user)); - when(passwordEncoder.matches("wrong", "encoded_pass")).thenReturn(false); - - assertThrows(NotValidationPasswordException.class, () -> authService.login(request)); - } -}