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

@@ -0,0 +1,79 @@
package com.yoyuzh.auth;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.yoyuzh.auth.dto.AuthResponse;
import com.yoyuzh.auth.dto.UserProfileResponse;
import com.yoyuzh.common.GlobalExceptionHandler;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import java.time.LocalDateTime;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@ExtendWith(MockitoExtension.class)
class AuthControllerValidationTest {
@Mock
private AuthService authService;
private MockMvc mockMvc;
private final ObjectMapper objectMapper = new ObjectMapper();
@BeforeEach
void setUp() {
mockMvc = MockMvcBuilders.standaloneSetup(new AuthController(authService))
.setControllerAdvice(new GlobalExceptionHandler())
.build();
}
@Test
void shouldReturnReadablePasswordValidationMessage() throws Exception {
mockMvc.perform(post("/api/auth/register")
.contentType(MediaType.APPLICATION_JSON)
.content("""
{
"username": "alice",
"email": "alice@example.com",
"password": "weakpass"
}
"""))
.andExpect(status().isBadRequest())
.andExpect(jsonPath("$.code").value(1000))
.andExpect(jsonPath("$.msg").value("密码至少10位且必须包含大写字母、小写字母、数字和特殊字符"));
}
@Test
void shouldExposeRefreshEndpointContract() throws Exception {
AuthResponse response = AuthResponse.issued(
"new-access-token",
"new-refresh-token",
new UserProfileResponse(7L, "alice", "alice@example.com", LocalDateTime.now())
);
when(authService.refresh("refresh-1")).thenReturn(response);
mockMvc.perform(post("/api/auth/refresh")
.contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(new Object() {
public final String refreshToken = "refresh-1";
})))
.andExpect(status().isOk())
.andExpect(jsonPath("$.code").value(0))
.andExpect(jsonPath("$.data.token").value("new-access-token"))
.andExpect(jsonPath("$.data.accessToken").value("new-access-token"))
.andExpect(jsonPath("$.data.refreshToken").value("new-refresh-token"))
.andExpect(jsonPath("$.data.user.username").value("alice"));
verify(authService).refresh("refresh-1");
}
}