This commit is contained in:
2026-08-03 13:16:19 +08:00
parent 481747d9dc
commit 9eb03d4bce
54 changed files with 1925 additions and 52 deletions
@@ -5,6 +5,7 @@ import org.junit.jupiter.api.Test;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.PostMapping;
import java.lang.reflect.Method;
@@ -35,6 +36,33 @@ class PlatformInternalUserContractTest {
"/api/platform/v1/iam/internal-users/{membershipId:\\d+}/roles");
}
@Test
void unifiedPlatformUserEndpointsKeepIndependentPermissions() throws Exception {
Method list = PlatformUserManagementController.class.getMethod("list",
com.baiyue.common.security.AuthenticatedUser.class);
Method create = PlatformUserManagementController.class.getMethod("create",
com.baiyue.iam.dto.PlatformUserManagementDtos.CreateUserRequest.class,
com.baiyue.common.security.AuthenticatedUser.class);
Method update = PlatformUserManagementController.class.getMethod("update", Long.class,
com.baiyue.iam.dto.PlatformUserManagementDtos.UpdateUserRequest.class,
com.baiyue.common.security.AuthenticatedUser.class);
Method status = PlatformUserManagementController.class.getMethod("status", Long.class,
com.baiyue.iam.dto.PlatformUserManagementDtos.ChangeStatusRequest.class,
com.baiyue.common.security.AuthenticatedUser.class);
Method password = PlatformUserManagementController.class.getMethod("password", Long.class,
com.baiyue.iam.dto.PlatformUserManagementDtos.ResetPasswordRequest.class,
com.baiyue.common.security.AuthenticatedUser.class);
assertEquals("hasAuthority('platform:user:list')", list.getAnnotation(PreAuthorize.class).value());
assertEquals("hasAuthority('platform:user:create') and hasAuthority('platform:user:grant-role')",
create.getAnnotation(PreAuthorize.class).value());
assertEquals("hasAuthority('platform:user:edit')", update.getAnnotation(PreAuthorize.class).value());
assertEquals("hasAuthority('platform:user:status')", status.getAnnotation(PreAuthorize.class).value());
assertEquals("hasAuthority('platform:user:reset-password')", password.getAnnotation(PreAuthorize.class).value());
assertNotNull(create.getAnnotation(PostMapping.class));
assertNotNull(update.getAnnotation(PutMapping.class));
}
@Test
void tenantProfileReadRequiresViewPermission() throws Exception {
Method method = MerchantTenantController.class.getMethod("profile",
@@ -0,0 +1,158 @@
package com.baiyue.iam.service;
import com.baiyue.common.core.api.ApiResponse;
import com.baiyue.common.core.exception.BizException;
import com.baiyue.iam.client.AuthAccountClient;
import com.baiyue.iam.dto.PlatformUserManagementDtos.*;
import com.baiyue.iam.entity.IamMembership;
import com.baiyue.iam.entity.IamRole;
import com.baiyue.iam.entity.IamTenant;
import com.baiyue.iam.entity.IamUser;
import com.baiyue.iam.mapper.IamRoleMapper;
import com.baiyue.iam.repository.MemberRepository;
import com.baiyue.iam.repository.TenantRepository;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.ArgumentCaptor;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Set;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.ArgumentMatchers.*;
import static org.mockito.Mockito.*;
class PlatformUserManagementServiceTest {
private final MemberRepository members = mock(MemberRepository.class);
private final TenantRepository tenants = mock(TenantRepository.class);
private final IamRoleMapper roles = mock(IamRoleMapper.class);
private final AuthAccountClient auth = mock(AuthAccountClient.class);
private final PlatformUserManagementService service =
new PlatformUserManagementService(members, tenants, roles, auth, "internal-token");
private IamTenant merchant;
private IamRole merchantRole;
private IamMembership membership;
private IamUser user;
@BeforeEach
void setUp() {
merchant = new IamTenant();
merchant.setId(10001L); merchant.setTenantType("MERCHANT"); merchant.setTenantName("华远贸易");
merchant.setStatus("ACTIVE");
merchantRole = new IamRole();
merchantRole.setId(40001L); merchantRole.setTenantId(10001L); merchantRole.setAppCode("MERCHANT");
merchantRole.setRoleName("租户管理员"); merchantRole.setStatus("ACTIVE");
membership = new IamMembership();
membership.setId(30L); membership.setTenantId(10001L); membership.setUserId(20L);
membership.setMemberType("EMPLOYEE"); membership.setMemberNo("MEMBER-30"); membership.setStatus("ACTIVE");
user = new IamUser();
user.setId(20L); user.setAuthUserId(10L); user.setUserType("ENTERPRISE");
user.setDisplayName("张伟"); user.setPhone("13800138000"); user.setStatus("ACTIVE");
when(tenants.findTenant(10001L)).thenReturn(merchant);
when(tenants.listMerchants()).thenReturn(List.of(merchant));
when(roles.selectById(40001L)).thenReturn(merchantRole);
when(roles.selectList(any())).thenReturn(List.of(merchantRole));
when(members.findById(30L)).thenReturn(membership);
when(members.findUser(20L)).thenReturn(user);
when(members.findRoleIds(10001L, 30L)).thenReturn(List.of(40001L));
when(auth.summary("internal-token", 10L)).thenReturn(ApiResponse.success(
new AuthAccountClient.AccountSummary(10L, "zhangwei", "张伟", "ACTIVE",
LocalDateTime.of(2026, 6, 1, 10, 30), 10001L, 30L, "MERCHANT")));
}
@Test
void listReturnsTenantRoleAndLastLoginForMerchantUser() {
when(members.findAll()).thenReturn(List.of(membership));
UserResponse response = service.list().get(0);
assertEquals("zhangwei", response.username());
assertEquals("华远贸易", response.tenantName());
assertEquals(List.of("租户管理员"), response.roleNames());
assertEquals(LocalDateTime.of(2026, 6, 1, 10, 30), response.lastLoginAt());
}
@Test
void createMerchantUserCreatesDisabledMerchantAccountAndMembership() {
when(auth.create(anyString(), any())).thenReturn(ApiResponse.success(
new AuthAccountClient.AccountSummary(99L, "newuser", "新用户", "DISABLED")));
when(auth.summary(anyString(), anyLong())).thenReturn(ApiResponse.success(
new AuthAccountClient.AccountSummary(99L, "newuser", "新用户", "DISABLED")));
when(members.findUser(anyLong())).thenReturn(user);
CreateUserRequest request = new CreateUserRequest("newuser", "新用户", "13900139000",
"new@example.com", 10001L, List.of(40001L), "Password1", "DISABLED");
service.create(request);
ArgumentCaptor<AuthAccountClient.CreateAccountRequest> account =
ArgumentCaptor.forClass(AuthAccountClient.CreateAccountRequest.class);
verify(auth).create(eq("internal-token"), account.capture());
assertEquals("MERCHANT", account.getValue().appCode());
assertEquals("DISABLED", account.getValue().accountStatus());
verify(members).insertUser(argThat(value -> "ENTERPRISE".equals(value.getUserType())));
verify(members).insert(argThat(value -> value.getTenantId() == 10001L
&& "DISABLED".equals(value.getStatus())));
}
@Test
void tenantMoveUpdatesAuthScopeAndRolesWhenOperatorCanGrantRoles() {
IamTenant target = new IamTenant();
target.setId(10002L); target.setTenantType("MERCHANT"); target.setTenantName("深圳速达"); target.setStatus("ACTIVE");
IamRole targetRole = new IamRole();
targetRole.setId(40002L); targetRole.setTenantId(10002L); targetRole.setAppCode("MERCHANT");
targetRole.setRoleName("操作员"); targetRole.setStatus("ACTIVE");
when(tenants.findTenant(10002L)).thenReturn(target);
when(tenants.listMerchants()).thenReturn(List.of(merchant, target));
when(roles.selectById(40002L)).thenReturn(targetRole);
when(roles.selectList(any())).thenReturn(List.of(merchantRole, targetRole));
when(auth.scope(anyString(), anyLong(), any())).thenReturn(ApiResponse.success(null));
when(auth.profile(anyString(), anyLong(), any())).thenReturn(ApiResponse.success(null));
UpdateUserRequest request = new UpdateUserRequest("张伟新", "13800138000", null,
10002L, List.of(40002L));
UserResponse response = service.update(30L, request, Set.of("platform:user:grant-role"));
verify(auth).scope(eq("internal-token"), eq(10L),
argThat(value -> value.tenantId() == 10002L && "MERCHANT".equals(value.appCode())));
verify(members).replaceRoles(10001L, 30L, List.of());
verify(members).replaceRoles(10002L, 30L, List.of(40002L));
assertEquals(10002L, response.tenantId());
}
@Test
void tenantOrRoleChangeRequiresGrantRolePermission() {
IamRole otherRole = new IamRole();
otherRole.setId(40003L); otherRole.setTenantId(10001L); otherRole.setAppCode("MERCHANT");
otherRole.setRoleName("操作员"); otherRole.setStatus("ACTIVE");
when(roles.selectById(40003L)).thenReturn(otherRole);
UpdateUserRequest request = new UpdateUserRequest("张伟", "13800138000", null,
10001L, List.of(40003L));
assertThrows(BizException.class, () -> service.update(30L, request, Set.of()));
verify(auth, never()).scope(anyString(), anyLong(), any());
}
@Test
void currentPlatformOperatorCannotDisableSelf() {
assertThrows(BizException.class,
() -> service.changeStatus(30L, new ChangeStatusRequest("DISABLED"), 30L));
verify(auth, never()).status(anyString(), anyLong(), any());
}
@Test
void builtInPlatformAdministratorCannotBeDisabled() {
membership.setTenantId(0L);
IamRole platformAdmin = new IamRole();
platformAdmin.setId(40000L); platformAdmin.setTenantId(0L); platformAdmin.setAppCode("PLATFORM");
platformAdmin.setRoleCode("PLATFORM_ADMIN"); platformAdmin.setRoleName("平台超级管理员");
platformAdmin.setStatus("ACTIVE");
when(roles.selectById(40000L)).thenReturn(platformAdmin);
when(members.findRoleIds(0L, 30L)).thenReturn(List.of(40000L));
assertThrows(BizException.class,
() -> service.changeStatus(30L, new ChangeStatusRequest("DISABLED"), 99L));
verify(auth, never()).status(anyString(), anyLong(), any());
}
}