feat(auth): harden token lifecycle and password policy

This commit is contained in:
yoyuzh
2026-03-19 14:51:18 +08:00
parent 41a83d2805
commit a78d0dc2db
26 changed files with 1047 additions and 53 deletions

View File

@@ -39,6 +39,9 @@ class AuthServiceTest {
@Mock
private JwtTokenProvider jwtTokenProvider;
@Mock
private RefreshTokenService refreshTokenService;
@Mock
private FileService fileService;
@@ -47,29 +50,32 @@ class AuthServiceTest {
@Test
void shouldRegisterUserWithEncryptedPassword() {
RegisterRequest request = new RegisterRequest("alice", "alice@example.com", "plain-password");
RegisterRequest request = new RegisterRequest("alice", "alice@example.com", "StrongPass1!");
when(userRepository.existsByUsername("alice")).thenReturn(false);
when(userRepository.existsByEmail("alice@example.com")).thenReturn(false);
when(passwordEncoder.encode("plain-password")).thenReturn("encoded-password");
when(passwordEncoder.encode("StrongPass1!")).thenReturn("encoded-password");
when(userRepository.save(any(User.class))).thenAnswer(invocation -> {
User user = invocation.getArgument(0);
user.setId(1L);
user.setCreatedAt(LocalDateTime.now());
return user;
});
when(jwtTokenProvider.generateToken(1L, "alice")).thenReturn("jwt-token");
when(jwtTokenProvider.generateAccessToken(1L, "alice")).thenReturn("access-token");
when(refreshTokenService.issueRefreshToken(any(User.class))).thenReturn("refresh-token");
AuthResponse response = authService.register(request);
assertThat(response.token()).isEqualTo("jwt-token");
assertThat(response.token()).isEqualTo("access-token");
assertThat(response.accessToken()).isEqualTo("access-token");
assertThat(response.refreshToken()).isEqualTo("refresh-token");
assertThat(response.user().username()).isEqualTo("alice");
verify(passwordEncoder).encode("plain-password");
verify(passwordEncoder).encode("StrongPass1!");
verify(fileService).ensureDefaultDirectories(any(User.class));
}
@Test
void shouldRejectDuplicateUsernameOnRegister() {
RegisterRequest request = new RegisterRequest("alice", "alice@example.com", "plain-password");
RegisterRequest request = new RegisterRequest("alice", "alice@example.com", "StrongPass1!");
when(userRepository.existsByUsername("alice")).thenReturn(true);
assertThatThrownBy(() -> authService.register(request))
@@ -87,17 +93,39 @@ class AuthServiceTest {
user.setPasswordHash("encoded-password");
user.setCreatedAt(LocalDateTime.now());
when(userRepository.findByUsername("alice")).thenReturn(Optional.of(user));
when(jwtTokenProvider.generateToken(1L, "alice")).thenReturn("jwt-token");
when(jwtTokenProvider.generateAccessToken(1L, "alice")).thenReturn("access-token");
when(refreshTokenService.issueRefreshToken(user)).thenReturn("refresh-token");
AuthResponse response = authService.login(request);
verify(authenticationManager).authenticate(
new UsernamePasswordAuthenticationToken("alice", "plain-password"));
assertThat(response.token()).isEqualTo("jwt-token");
assertThat(response.token()).isEqualTo("access-token");
assertThat(response.accessToken()).isEqualTo("access-token");
assertThat(response.refreshToken()).isEqualTo("refresh-token");
assertThat(response.user().email()).isEqualTo("alice@example.com");
verify(fileService).ensureDefaultDirectories(user);
}
@Test
void shouldRotateRefreshTokenAndReturnNewCredentials() {
User user = new User();
user.setId(1L);
user.setUsername("alice");
user.setEmail("alice@example.com");
user.setCreatedAt(LocalDateTime.now());
when(refreshTokenService.rotateRefreshToken("old-refresh"))
.thenReturn(new RefreshTokenService.RotatedRefreshToken(user, "new-refresh"));
when(jwtTokenProvider.generateAccessToken(1L, "alice")).thenReturn("new-access");
AuthResponse response = authService.refresh("old-refresh");
assertThat(response.token()).isEqualTo("new-access");
assertThat(response.accessToken()).isEqualTo("new-access");
assertThat(response.refreshToken()).isEqualTo("new-refresh");
assertThat(response.user().username()).isEqualTo("alice");
}
@Test
void shouldThrowBusinessExceptionWhenAuthenticationFails() {
LoginRequest request = new LoginRequest("alice", "wrong-password");
@@ -119,11 +147,14 @@ class AuthServiceTest {
user.setCreatedAt(LocalDateTime.now());
return user;
});
when(jwtTokenProvider.generateToken(9L, "demo")).thenReturn("jwt-token");
when(jwtTokenProvider.generateAccessToken(9L, "demo")).thenReturn("access-token");
when(refreshTokenService.issueRefreshToken(any(User.class))).thenReturn("refresh-token");
AuthResponse response = authService.devLogin("demo");
assertThat(response.user().username()).isEqualTo("demo");
assertThat(response.accessToken()).isEqualTo("access-token");
assertThat(response.refreshToken()).isEqualTo("refresh-token");
verify(fileService).ensureDefaultDirectories(any(User.class));
}
}