feat(auth): POST /auth/login retourne email, name, role et token
CI — Tests & Docker Build / Tests (push) Failing after 4s
CI — Tests & Docker Build / Build & push image Docker (push) Has been skipped

- Champ `name` ajouté sur User, UserEntity, RegisterRequest
- AuthenticateUserUseCase retourne Result(user, token) au lieu du token seul
- UserNotFoundException remplacé par BadCredentialsException au login (pas de fuite d'info)
- @Email retiré de LoginRequest (identifiant = "gato", pas nécessairement un email)
- Migration V2 : colonne name + utilisateur par défaut gato/change (ADMIN)
- bytecode cible Java 21 (ASM Spring Boot 3.4 ne supporte pas Java 25)
- Tests : AbstractIntegrationTest simplifié, URL TC JDBC + network host

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-06-07 08:24:41 +02:00
parent c34cc41496
commit 12a28af1ca
19 changed files with 64 additions and 42 deletions
@@ -1,7 +1,10 @@
package com.olhar.olharapi.application.port.in;
import com.olhar.olharapi.domain.model.User;
public interface AuthenticateUserUseCase {
String authenticate(Command command);
Result authenticate(Command command);
record Command(String email, String password) {}
record Result(User user, String token) {}
}
@@ -5,5 +5,5 @@ import com.olhar.olharapi.domain.model.User;
public interface RegisterUserUseCase {
User register(Command command);
record Command(String email, String password) {}
record Command(String email, String name, String password) {}
}
@@ -2,7 +2,6 @@ package com.olhar.olharapi.application.usecase;
import com.olhar.olharapi.application.port.in.AuthenticateUserUseCase;
import com.olhar.olharapi.application.port.out.UserRepository;
import com.olhar.olharapi.domain.exception.UserNotFoundException;
import com.olhar.olharapi.domain.model.User;
import com.olhar.olharapi.infrastructure.security.JwtService;
import lombok.RequiredArgsConstructor;
@@ -19,14 +18,14 @@ public class AuthenticateUserService implements AuthenticateUserUseCase {
private final JwtService jwtService;
@Override
public String authenticate(Command command) {
public Result authenticate(Command command) {
User user = userRepository.findByEmail(command.email())
.orElseThrow(() -> new UserNotFoundException(command.email()));
.orElseThrow(() -> new BadCredentialsException("Identifiants invalides"));
if (!passwordEncoder.matches(command.password(), user.passwordHash())) {
throw new BadCredentialsException("Invalid credentials");
throw new BadCredentialsException("Identifiants invalides");
}
return jwtService.generateToken(user);
return new Result(user, jwtService.generateToken(user));
}
}
@@ -29,6 +29,7 @@ public class RegisterUserService implements RegisterUserUseCase {
User user = new User(
UUID.randomUUID(),
command.email(),
command.name(),
passwordEncoder.encode(command.password()),
User.Role.USER,
Instant.now()
@@ -6,11 +6,16 @@ import java.util.UUID;
public record User(
UUID id,
String email,
String name,
String passwordHash,
Role role,
Instant createdAt
) {
public enum Role {
USER, ADMIN
USER, ADMIN;
public String toApiRole() {
return this == ADMIN ? "admin" : "member";
}
}
}
@@ -21,6 +21,9 @@ public class UserEntity {
@Column(nullable = false, unique = true)
private String email;
@Column(nullable = false)
private String name;
@Column(name = "password_hash", nullable = false)
private String passwordHash;
@@ -11,6 +11,7 @@ public class UserPersistenceMapper {
return new User(
entity.getId(),
entity.getEmail(),
entity.getName(),
entity.getPasswordHash(),
User.Role.valueOf(entity.getRole().name()),
entity.getCreatedAt()
@@ -21,6 +22,7 @@ public class UserPersistenceMapper {
return UserEntity.builder()
.id(user.id())
.email(user.email())
.name(user.name())
.passwordHash(user.passwordHash())
.role(UserEntity.RoleEnum.valueOf(user.role().name()))
.createdAt(user.createdAt())
@@ -30,7 +30,7 @@ public class AuthController {
@Operation(summary = "Créer un compte utilisateur")
public UserResponse register(@Valid @RequestBody RegisterRequest request) {
User user = registerUserUseCase.register(
new RegisterUserUseCase.Command(request.email(), request.password())
new RegisterUserUseCase.Command(request.email(), request.name(), request.password())
);
return userRestMapper.toResponse(user);
}
@@ -38,9 +38,10 @@ public class AuthController {
@PostMapping("/login")
@Operation(summary = "S'authentifier et obtenir un token JWT")
public AuthResponse login(@Valid @RequestBody LoginRequest request) {
String token = authenticateUserUseCase.authenticate(
AuthenticateUserUseCase.Result result = authenticateUserUseCase.authenticate(
new AuthenticateUserUseCase.Command(request.email(), request.password())
);
return new AuthResponse(token);
User user = result.user();
return new AuthResponse(user.email(), user.name(), user.role().toApiRole(), result.token());
}
}
@@ -4,6 +4,6 @@ import jakarta.validation.constraints.Email;
import jakarta.validation.constraints.NotBlank;
public record LoginRequest(
@Email @NotBlank String email,
@NotBlank String email,
@NotBlank String password
) {}
@@ -6,5 +6,6 @@ import jakarta.validation.constraints.Size;
public record RegisterRequest(
@Email @NotBlank String email,
@NotBlank String name,
@NotBlank @Size(min = 8) String password
) {}
@@ -1,3 +1,3 @@
package com.olhar.olharapi.interfaces.rest.dto.response;
public record AuthResponse(String token) {}
public record AuthResponse(String email, String name, String role, String token) {}
@@ -3,4 +3,4 @@ package com.olhar.olharapi.interfaces.rest.dto.response;
import java.time.Instant;
import java.util.UUID;
public record UserResponse(UUID id, String email, String role, Instant createdAt) {}
public record UserResponse(UUID id, String email, String name, String role, Instant createdAt) {}
@@ -11,7 +11,8 @@ public class UserRestMapper {
return new UserResponse(
user.id(),
user.email(),
user.role().name(),
user.name(),
user.role().toApiRole(),
user.createdAt()
);
}
@@ -0,0 +1,11 @@
ALTER TABLE users ADD COLUMN name VARCHAR(255) NOT NULL DEFAULT '';
INSERT INTO users (id, email, name, password_hash, role, created_at)
VALUES (
gen_random_uuid(),
'gato',
'Gato',
'$2a$10$53jNzmKK21BVNrhrAToFouWoO/agW3TVe8j7nusbrYRVqALp/MALK',
'ADMIN',
now()
) ON CONFLICT (email) DO NOTHING;