暂存提交
This commit is contained in:
@@ -0,0 +1,52 @@
|
||||
package com.baiyue.auth.service;
|
||||
|
||||
import com.baiyue.auth.dto.AccountManagementDtos.ChangePasswordRequest;
|
||||
import com.baiyue.auth.dto.AccountManagementDtos.UpdateAccountStatusRequest;
|
||||
import com.baiyue.auth.entity.AuthAccount;
|
||||
import com.baiyue.auth.repository.AuthAccountRepository;
|
||||
import com.baiyue.common.core.exception.BizException;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
||||
import org.springframework.test.util.ReflectionTestUtils;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
class AccountManagementServiceTest {
|
||||
private final AuthAccountRepository repository = mock(AuthAccountRepository.class);
|
||||
private final TokenSessionStore sessions = mock(TokenSessionStore.class);
|
||||
private final BCryptPasswordEncoder encoder = new BCryptPasswordEncoder(4);
|
||||
private final AccountManagementService service = new AccountManagementService();
|
||||
private AuthAccount account;
|
||||
|
||||
@BeforeEach void setUp() {
|
||||
ReflectionTestUtils.setField(service, "repository", repository);
|
||||
ReflectionTestUtils.setField(service, "passwordEncoder", encoder);
|
||||
ReflectionTestUtils.setField(service, "tokenSessionStore", sessions);
|
||||
account = new AuthAccount(); account.setId(10L); account.setPasswordHash(encoder.encode("OldPass1"));
|
||||
account.setTokenVersion(2); account.setAccountStatus("ACTIVE");
|
||||
when(repository.findById(10L)).thenReturn(account);
|
||||
}
|
||||
|
||||
@Test void 修改密码校验旧密码并撤销全部会话() {
|
||||
service.changePassword(10L, new ChangePasswordRequest("OldPass1", "NewPass2"));
|
||||
assertTrue(encoder.matches("NewPass2", account.getPasswordHash()));
|
||||
assertEquals(3, account.getTokenVersion());
|
||||
verify(repository).save(account);
|
||||
verify(sessions).revokeAll(10L);
|
||||
}
|
||||
|
||||
@Test void 原密码错误不得写入() {
|
||||
assertThrows(BizException.class,
|
||||
() -> service.changePassword(10L, new ChangePasswordRequest("WrongPass1", "NewPass2")));
|
||||
verify(repository, never()).save(any());
|
||||
verify(sessions, never()).revokeAll(any());
|
||||
}
|
||||
|
||||
@Test void 停用账号撤销全部会话() {
|
||||
service.updateStatus(10L, new UpdateAccountStatusRequest("DISABLED"));
|
||||
assertEquals("DISABLED", account.getAccountStatus());
|
||||
verify(sessions).revokeAll(10L);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
package com.baiyue.auth.service;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.data.redis.core.StringRedisTemplate;
|
||||
import org.springframework.data.redis.core.ValueOperations;
|
||||
import org.springframework.data.redis.core.SetOperations;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.Set;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.ArgumentMatchers.anyString;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
import static org.mockito.Mockito.eq;
|
||||
|
||||
class TokenSessionStoreTest {
|
||||
@Test
|
||||
void storesAccessAndHashedRefreshWithIndependentTtls() {
|
||||
StringRedisTemplate redis = mock(StringRedisTemplate.class);
|
||||
@SuppressWarnings("unchecked")
|
||||
ValueOperations<String, String> values = mock(ValueOperations.class);
|
||||
when(redis.opsForValue()).thenReturn(values);
|
||||
TokenSessionStore store = new TokenSessionStore(redis, new ObjectMapper(), "baiyue:auth:");
|
||||
|
||||
store.store("jti-1", 42L, "raw-refresh", Duration.ofMinutes(30), Duration.ofDays(7));
|
||||
|
||||
verify(values).set("baiyue:auth:access:jti-1", "42", Duration.ofMinutes(30));
|
||||
verify(values).set(org.mockito.ArgumentMatchers.startsWith("baiyue:auth:refresh:"),
|
||||
org.mockito.ArgumentMatchers.contains("\"userId\":42"), org.mockito.ArgumentMatchers.eq(Duration.ofDays(7)));
|
||||
}
|
||||
|
||||
@Test
|
||||
void atomicallyConsumesRefreshAndRevokesItsAccessSession() throws Exception {
|
||||
StringRedisTemplate redis = mock(StringRedisTemplate.class);
|
||||
@SuppressWarnings("unchecked")
|
||||
ValueOperations<String, String> values = mock(ValueOperations.class);
|
||||
when(redis.opsForValue()).thenReturn(values);
|
||||
String json = new ObjectMapper().writeValueAsString(
|
||||
new TokenSessionStore.RefreshSession(42L, "jti-1"));
|
||||
when(values.getAndDelete(anyString())).thenReturn(json);
|
||||
TokenSessionStore store = new TokenSessionStore(redis, new ObjectMapper(), "baiyue:auth");
|
||||
|
||||
TokenSessionStore.RefreshSession session = store.consume("raw-refresh");
|
||||
|
||||
assertThat(session.userId()).isEqualTo(42L);
|
||||
assertThat(session.accessJwtId()).isEqualTo("jti-1");
|
||||
verify(values).getAndDelete(org.mockito.ArgumentMatchers.startsWith("baiyue:auth:refresh:"));
|
||||
verify(redis).delete("baiyue:auth:access:jti-1");
|
||||
}
|
||||
|
||||
@Test
|
||||
void treatsAlreadyConsumedRefreshAsInvalid() {
|
||||
StringRedisTemplate redis = mock(StringRedisTemplate.class);
|
||||
@SuppressWarnings("unchecked")
|
||||
ValueOperations<String, String> values = mock(ValueOperations.class);
|
||||
when(redis.opsForValue()).thenReturn(values);
|
||||
when(values.getAndDelete(anyString())).thenReturn(null);
|
||||
|
||||
assertThat(new TokenSessionStore(redis, new ObjectMapper(), "baiyue:auth")
|
||||
.consume("raw-refresh")).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
void revokesAllIndexedSessionsForUser() {
|
||||
StringRedisTemplate redis = mock(StringRedisTemplate.class);
|
||||
@SuppressWarnings("unchecked")
|
||||
SetOperations<String, String> sets = mock(SetOperations.class);
|
||||
when(redis.opsForSet()).thenReturn(sets);
|
||||
when(sets.members("baiyue:auth:user-sessions:42"))
|
||||
.thenReturn(Set.of("baiyue:auth:access:a", "baiyue:auth:refresh:b"));
|
||||
|
||||
new TokenSessionStore(redis, new ObjectMapper(), "baiyue:auth").revokeAll(42L);
|
||||
|
||||
verify(redis).delete(eq(Set.of("baiyue:auth:access:a", "baiyue:auth:refresh:b")));
|
||||
verify(redis).delete("baiyue:auth:user-sessions:42");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user