This commit is contained in:
2026-08-10 12:27:16 +08:00
parent eab51bc5ac
commit 14929bb257
3 changed files with 117 additions and 1 deletions
@@ -0,0 +1,83 @@
package com.baiyue.auth.service;
import com.baiyue.auth.client.AuthorizationLoader;
import com.baiyue.auth.client.AuthorizationSnapshot;
import com.baiyue.auth.config.AuthSecurityProperties;
import com.baiyue.auth.dto.LoginRequest;
import com.baiyue.auth.entity.AuthAccount;
import com.baiyue.auth.repository.AuthAccountRepository;
import org.junit.jupiter.api.Test;
import org.mockito.ArgumentCaptor;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.jwt.Jwt;
import org.springframework.security.oauth2.jwt.JwtEncoder;
import org.springframework.security.oauth2.jwt.JwtEncoderParameters;
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
import jakarta.annotation.Resource;
import java.time.Duration;
import java.util.Set;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@SpringJUnitConfig(classes = {AuthService.class, AuthServiceSmallJwtTest.TestConfig.class})
class AuthServiceSmallJwtTest {
@MockBean private AuthAccountRepository repository;
@MockBean private PasswordEncoder passwordEncoder;
@MockBean private JwtEncoder jwtEncoder;
@MockBean private AuthorizationLoader authorizationLoader;
@MockBean private TokenSessionStore tokenSessionStore;
@Resource private AuthService service;
@Configuration(proxyBeanMethods = false)
static class TestConfig {
@Bean
AuthSecurityProperties properties() {
return new AuthSecurityProperties("unused", "auth-service", Duration.ofMinutes(30),
Duration.ofDays(7), 5, Duration.ofMinutes(10));
}
}
@Test
void signsIdentityOnlyJwtAndStoresAuthorizationInRedis() {
AuthAccount account = new AuthAccount();
account.setId(42L);
account.setUsername("operator");
account.setPasswordHash("hash");
account.setAccountStatus("ACTIVE");
account.setDefaultTenantId(0L);
account.setOperatorTenantId(0L);
account.setDefaultMembershipId(84L);
account.setDefaultAppCode("PLATFORM");
account.setTokenVersion(1);
AuthorizationSnapshot snapshot = new AuthorizationSnapshot(42L, 0L, 84L, "PLATFORM",
"WEB", Set.of("PLATFORM_ADMIN"), Set.of("platform:order:list"));
Jwt encoded = org.mockito.Mockito.mock(Jwt.class);
when(repository.findByUsername("operator")).thenReturn(account);
when(passwordEncoder.matches("secret", "hash")).thenReturn(true);
when(authorizationLoader.load(account)).thenReturn(snapshot);
when(jwtEncoder.encode(any())).thenReturn(encoded);
when(encoded.getTokenValue()).thenReturn("small-token");
service.login(new LoginRequest("operator", "secret"));
ArgumentCaptor<JwtEncoderParameters> jwt = ArgumentCaptor.forClass(JwtEncoderParameters.class);
verify(jwtEncoder).encode(jwt.capture());
assertThat(jwt.getValue().getClaims().getClaims())
.containsEntry("user_id", 42L)
.containsEntry("membership_id", 84L)
.doesNotContainKeys("roles", "permissions", "authorities", "scope");
verify(tokenSessionStore).store(any(), org.mockito.ArgumentMatchers.eq(42L),
org.mockito.ArgumentMatchers.eq(Set.of("PLATFORM_ADMIN")),
org.mockito.ArgumentMatchers.eq(Set.of("platform:order:list")), any(),
org.mockito.ArgumentMatchers.eq(Duration.ofMinutes(30)),
org.mockito.ArgumentMatchers.eq(Duration.ofDays(7)));
}
}
@@ -349,6 +349,22 @@ class RbacServiceTest {
eq(new AuthAccountClient.RevokeAccountSessionsRequest(Set.of(501L))));
}
@Test
void permissionStatusChangeRevokesMembersOfEveryGrantedRole() {
IamPermission custom = permission(21L, 100L, "merchant:custom:edit");
when(repository.findOwnedPermission(21L, 100L, "MERCHANT")).thenReturn(custom);
when(repository.findRoleIdsByPermission(100L, 21L)).thenReturn(Set.of(11L, 12L));
when(repository.findAssignedAuthUserIds(100L, 11L)).thenReturn(List.of(501L, 502L));
when(repository.findAssignedAuthUserIds(100L, 12L)).thenReturn(List.of(502L, 503L));
when(authClient.revokeSessions(any(), any())).thenReturn(ApiResponse.success(null));
service.changePermissionStatus(100L, "MERCHANT", 21L,
new ChangePermissionStatusRequest("DISABLED"));
verify(authClient).revokeSessions(eq("test-internal-token"),
eq(new AuthAccountClient.RevokeAccountSessionsRequest(Set.of(501L, 502L, 503L))));
}
@Test
void authFailureRejectsRoleStatusChangeSoIamTransactionCanRollBack() {
IamRole role = role(11L, 100L, "MERCHANT", "CUSTOM");
@@ -3,6 +3,23 @@ package com.baiyue.order.mapper;
import com.baiyue.order.entity.OrderFulfillmentSplitEntity;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import com.baiyue.order.entity.OrderEntity;
import java.util.List;
@Mapper
public interface OrderFulfillmentSplitMapper extends BaseMapper<OrderFulfillmentSplitEntity> {}
public interface OrderFulfillmentSplitMapper extends BaseMapper<OrderFulfillmentSplitEntity> {
@Select("SELECT * FROM ord_order WHERE tenant_id=#{tenantId} AND id=#{orderId} AND deleted=0 FOR UPDATE")
OrderEntity lockOrder(@Param("tenantId") long tenantId, @Param("orderId") long orderId);
@Select("SELECT * FROM ord_order_fulfillment_split WHERE tenant_id=#{tenantId} AND parent_order_id=#{parentOrderId} AND idempotency_key=#{key} ORDER BY id")
List<OrderFulfillmentSplitEntity> findByIdempotency(@Param("tenantId") long tenantId,
@Param("parentOrderId") long parentOrderId,
@Param("key") String key);
@Select("SELECT * FROM ord_order_fulfillment_split WHERE tenant_id=#{tenantId} AND parent_order_id=#{parentOrderId} ORDER BY created_at,id")
List<OrderFulfillmentSplitEntity> findByParent(@Param("tenantId") long tenantId,
@Param("parentOrderId") long parentOrderId);
}