From 14929bb25780596eeb41367c8f173462e7829fff Mon Sep 17 00:00:00 2001 From: ouyangxq <775153912@qq.com> Date: Mon, 10 Aug 2026 12:27:16 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../auth/service/AuthServiceSmallJwtTest.java | 83 +++++++++++++++++++ .../baiyue/iam/service/RbacServiceTest.java | 16 ++++ .../mapper/OrderFulfillmentSplitMapper.java | 19 ++++- 3 files changed, 117 insertions(+), 1 deletion(-) create mode 100644 auth/src/test/java/com/baiyue/auth/service/AuthServiceSmallJwtTest.java diff --git a/auth/src/test/java/com/baiyue/auth/service/AuthServiceSmallJwtTest.java b/auth/src/test/java/com/baiyue/auth/service/AuthServiceSmallJwtTest.java new file mode 100644 index 000000000..cfaf78348 --- /dev/null +++ b/auth/src/test/java/com/baiyue/auth/service/AuthServiceSmallJwtTest.java @@ -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 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))); + } +} diff --git a/iam/src/test/java/com/baiyue/iam/service/RbacServiceTest.java b/iam/src/test/java/com/baiyue/iam/service/RbacServiceTest.java index 59f4a43c7..228deafe6 100644 --- a/iam/src/test/java/com/baiyue/iam/service/RbacServiceTest.java +++ b/iam/src/test/java/com/baiyue/iam/service/RbacServiceTest.java @@ -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"); diff --git a/order/src/main/java/com/baiyue/order/mapper/OrderFulfillmentSplitMapper.java b/order/src/main/java/com/baiyue/order/mapper/OrderFulfillmentSplitMapper.java index dbfeffa3c..4a0100317 100644 --- a/order/src/main/java/com/baiyue/order/mapper/OrderFulfillmentSplitMapper.java +++ b/order/src/main/java/com/baiyue/order/mapper/OrderFulfillmentSplitMapper.java @@ -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 {} +public interface OrderFulfillmentSplitMapper extends BaseMapper { + @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 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 findByParent(@Param("tenantId") long tenantId, + @Param("parentOrderId") long parentOrderId); +}