INC-1 add login function

This commit is contained in:
vladp
2025-11-25 11:59:37 +07:00
parent 3626a51b57
commit 74ae769de0
9 changed files with 139 additions and 41 deletions
@@ -30,12 +30,10 @@ public class AuthController {
}
@PostMapping("/login")
public ResponseEntity<LoginResponse> login(@RequestBody LoginRequest request) {
//TODO add try-catch and response code
// try {
return ResponseEntity.ok(authService.login(request));
// } catch (RuntimeException e) {
// return ResponseEntity.badRequest();
// }
public ResponseEntity<LoginResponse> login(@Valid @RequestBody LoginRequest request) {
AuthToken login = authService.login(request);
return ResponseEntity.ok(new LoginResponse(true, login.getUser().getEmail(),
login.getToken(),login.getExpiresAt().toString()));
}
}
@@ -1,12 +1,18 @@
package ru.soune.no_copy.dto;
import jakarta.validation.constraints.Email;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Size;
import lombok.AllArgsConstructor;
import lombok.Data;
@Data
@AllArgsConstructor
public class LoginRequest {
@NotBlank(message = "error.not.blank") @Email(message = "error.not.email") @Size(max = 128)
private String email;
@NotBlank(message = "error.not.blank") @Size(min = 8)
private String password;
}
@@ -1,13 +1,14 @@
package ru.soune.no_copy.dto;
import lombok.AllArgsConstructor;
import lombok.Data;
import ru.soune.no_copy.entity.User;
@Data
@AllArgsConstructor
public class LoginResponse {
private boolean success;
private String message;
private User user;
private String email;
private String token;
private String expiresAt;
}
@@ -8,6 +8,6 @@ public record RegisterRequest(
@NotBlank(message = "error.name.length") @Size(min = 2, max = 64) String firstName,
@NotBlank(message = "error.name.length") @Size(min = 2, max = 64) String secondName,
@NotBlank(message = "error.name.length") @Size(min = 2, max = 64) String lastName,
@NotBlank(message = "error.not.blank") @Email(message = "error.not.email") @Size(max = 128)String email,
@NotBlank(message = "error.not.blank") @Email(message = "error.not.email") @Size(max = 128) String email,
@NotBlank(message = "error.not.blank") @Size(min = 8) String password
) {}
@@ -0,0 +1,7 @@
package ru.soune.no_copy.exception;
public class NotValidationPasswordException extends RuntimeException {
public NotValidationPasswordException(String message) {
super(message);
}
}
@@ -0,0 +1,7 @@
package ru.soune.no_copy.exception;
public class UserNotFoundException extends RuntimeException {
public UserNotFoundException(String message) {
super(message);
}
}
@@ -8,7 +8,9 @@ import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import ru.soune.no_copy.exception.NotValidationPasswordException;
import ru.soune.no_copy.exception.UserAlreadyExistsException;
import ru.soune.no_copy.exception.UserNotFoundException;
import java.util.Map;
@@ -39,4 +41,26 @@ public class GlobalExceptionHandler {
"message" ,ex.getMessage()
));
}
@ExceptionHandler(UserNotFoundException.class)
@ResponseStatus(HttpStatus.NOT_FOUND)
public ResponseEntity<?> handleUserNotFoundException(UserNotFoundException ex) {
return ResponseEntity.
badRequest()
.body(Map.of(
"success", false,
"message" ,ex.getMessage()
));
}
@ExceptionHandler(NotValidationPasswordException.class)
@ResponseStatus(HttpStatus.FORBIDDEN)
public ResponseEntity<?> handleNotValidationPasswordException(NotValidationPasswordException ex) {
return ResponseEntity.
badRequest()
.body(Map.of(
"success", false,
"message" ,ex.getMessage()
));
}
}
@@ -6,17 +6,17 @@ import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import ru.soune.no_copy.dto.LoginRequest;
import ru.soune.no_copy.dto.LoginResponse;
import ru.soune.no_copy.dto.RegisterRequest;
import ru.soune.no_copy.entity.AuthToken;
import ru.soune.no_copy.entity.User;
import ru.soune.no_copy.exception.NotValidationPasswordException;
import ru.soune.no_copy.exception.UserAlreadyExistsException;
import ru.soune.no_copy.exception.UserNotFoundException;
import ru.soune.no_copy.repository.AuthTokenRepository;
import ru.soune.no_copy.repository.UserRepository;
import java.security.SecureRandom;
import java.time.LocalDateTime;
import java.util.HexFormat;
import java.util.Base64;
import java.util.Locale;
import java.util.Optional;
@@ -32,6 +32,8 @@ public class AuthService {
private final MessageSource messageSource;
private final SecureRandom secureRandom = new SecureRandom();
@Transactional
public AuthToken register(RegisterRequest registerRequest) {
if (userRepository.existsByEmail(registerRequest.email())) {
@@ -49,48 +51,37 @@ public class AuthService {
User savedUser = userRepository.save(user);
AuthToken authToken = new AuthToken();
authToken.setToken(generateToken());
authToken.setToken(generateAuthToken());
authToken.setUser(savedUser);
return authTokenRepository.save(authToken);
}
public LoginResponse login(LoginRequest request) {
@Transactional
public AuthToken login(LoginRequest request) {
Optional<User> userOpt = userRepository.findByEmail(request.getEmail());
if (userOpt.isEmpty()) {
//ADD EXCEPTION
throw new UserNotFoundException("User with email " + request.getEmail() + " not found");
}
User user = userOpt.get();
if (!passwordEncoder.matches(request.getPassword(), user.getPassword())) {
//ADD EXCEPTION
throw new NotValidationPasswordException("Invalid password");
}
String token = generateToken();
LocalDateTime expiresAt = LocalDateTime.now().plusDays(30);
AuthToken authToken = new AuthToken();
authToken.setToken(generateToken());
authToken.setToken(generateAuthToken());
authToken.setUser(user);
authTokenRepository.save(authToken);
userRepository.save(user);
LoginResponse response = new LoginResponse();
response.setSuccess(true);
// response.setMessage(""); add message
response.setUser(user);
response.setToken(token);
response.setExpiresAt(expiresAt.toString());
return response;
return authTokenRepository.save(authToken);
}
//TODO change logic generate token
private String generateToken() {
private String generateAuthToken() {
byte[] bytes = new byte[32];
new SecureRandom().nextBytes(bytes);
return HexFormat.of().formatHex(bytes);
secureRandom.nextBytes(bytes);
return Base64.getUrlEncoder().withoutPadding().encodeToString(bytes);
}
}