335 lines
15 KiB
Java
335 lines
15 KiB
Java
package com.danyang.match.platform.invariants;
|
||||
|
|
|
|||
|
|
import com.danyang.match.platform.shared.constant.Constants;
|
|||
|
|
import org.junit.jupiter.api.*;
|
|||
|
|
|
|||
|
|
import java.util.*;
|
|||
|
|
|
|||
|
|
import static org.junit.jupiter.api.Assertions.*;
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 必须永久存在的权限测试矩阵
|
|||
|
|
* 每次CI都运行 — 保护9角色×8模块权限边界
|
|||
|
|
*/
|
|||
|
|
class PermissionMatrixTest {
|
|||
|
|
|
|||
|
|
// 角色权限矩阵定义
|
|||
|
|
// Row = Role, Column = Permission Module
|
|||
|
|
private static final Map<String, Map<String, Boolean>> PERMISSION_MATRIX = new LinkedHashMap<>();
|
|||
|
|
|
|||
|
|
static {
|
|||
|
|
// super_admin: 全部权限
|
|||
|
|
Map<String, Boolean> superAdmin = new HashMap<>();
|
|||
|
|
superAdmin.put("user.view", true);
|
|||
|
|
superAdmin.put("user.sensitive.view", true);
|
|||
|
|
superAdmin.put("user.status.change", true);
|
|||
|
|
superAdmin.put("review.view", true);
|
|||
|
|
superAdmin.put("review.process", true);
|
|||
|
|
superAdmin.put("matchmaker.view", true);
|
|||
|
|
superAdmin.put("matchmaker.assign", true);
|
|||
|
|
superAdmin.put("matchmaker.service", true);
|
|||
|
|
superAdmin.put("activity.view", true);
|
|||
|
|
superAdmin.put("activity.create", true);
|
|||
|
|
superAdmin.put("activity.review_registration", true);
|
|||
|
|
superAdmin.put("risk.report.view", true);
|
|||
|
|
superAdmin.put("risk.report.process", true);
|
|||
|
|
superAdmin.put("risk.user.ban", true);
|
|||
|
|
superAdmin.put("organization.manage", true);
|
|||
|
|
superAdmin.put("permission.manage", true);
|
|||
|
|
superAdmin.put("analytics.view", true);
|
|||
|
|
superAdmin.put("data.export", true);
|
|||
|
|
PERMISSION_MATRIX.put("super_admin", superAdmin);
|
|||
|
|
|
|||
|
|
// platform_admin: 大部分权限,无permission.manage
|
|||
|
|
Map<String, Boolean> platformAdmin = new HashMap<>();
|
|||
|
|
platformAdmin.put("user.view", true);
|
|||
|
|
platformAdmin.put("user.sensitive.view", true);
|
|||
|
|
platformAdmin.put("user.status.change", true);
|
|||
|
|
platformAdmin.put("review.view", true);
|
|||
|
|
platformAdmin.put("review.process", true);
|
|||
|
|
platformAdmin.put("matchmaker.view", true);
|
|||
|
|
platformAdmin.put("matchmaker.assign", true);
|
|||
|
|
platformAdmin.put("matchmaker.service", true);
|
|||
|
|
platformAdmin.put("activity.view", true);
|
|||
|
|
platformAdmin.put("activity.create", true);
|
|||
|
|
platformAdmin.put("activity.review_registration", true);
|
|||
|
|
platformAdmin.put("risk.report.view", true);
|
|||
|
|
platformAdmin.put("risk.report.process", true);
|
|||
|
|
platformAdmin.put("risk.user.ban", true);
|
|||
|
|
platformAdmin.put("organization.manage", true);
|
|||
|
|
platformAdmin.put("permission.manage", false); // 不能管理权限
|
|||
|
|
platformAdmin.put("analytics.view", true);
|
|||
|
|
platformAdmin.put("data.export", true);
|
|||
|
|
PERMISSION_MATRIX.put("platform_admin", platformAdmin);
|
|||
|
|
|
|||
|
|
// organization_admin: 本机构范围内
|
|||
|
|
Map<String, Boolean> orgAdmin = new HashMap<>();
|
|||
|
|
orgAdmin.put("user.view", true); // 本机构用户
|
|||
|
|
orgAdmin.put("user.sensitive.view", false);
|
|||
|
|
orgAdmin.put("user.status.change", false);
|
|||
|
|
orgAdmin.put("review.view", true);
|
|||
|
|
orgAdmin.put("review.process", true);
|
|||
|
|
orgAdmin.put("matchmaker.view", true);
|
|||
|
|
orgAdmin.put("matchmaker.assign", false);
|
|||
|
|
orgAdmin.put("matchmaker.service", true);
|
|||
|
|
orgAdmin.put("activity.view", true);
|
|||
|
|
orgAdmin.put("activity.create", true);
|
|||
|
|
orgAdmin.put("activity.review_registration", true);
|
|||
|
|
orgAdmin.put("risk.report.view", false);
|
|||
|
|
orgAdmin.put("risk.report.process", false);
|
|||
|
|
orgAdmin.put("risk.user.ban", false);
|
|||
|
|
orgAdmin.put("organization.manage", true);
|
|||
|
|
orgAdmin.put("permission.manage", false);
|
|||
|
|
orgAdmin.put("analytics.view", true);
|
|||
|
|
orgAdmin.put("data.export", false);
|
|||
|
|
PERMISSION_MATRIX.put("organization_admin", orgAdmin);
|
|||
|
|
|
|||
|
|
// reviewer: 仅审核
|
|||
|
|
Map<String, Boolean> reviewer = new HashMap<>();
|
|||
|
|
reviewer.put("user.view", false);
|
|||
|
|
reviewer.put("user.sensitive.view", false);
|
|||
|
|
reviewer.put("user.status.change", false);
|
|||
|
|
reviewer.put("review.view", true);
|
|||
|
|
reviewer.put("review.process", true);
|
|||
|
|
reviewer.put("matchmaker.view", false);
|
|||
|
|
reviewer.put("matchmaker.assign", false);
|
|||
|
|
reviewer.put("matchmaker.service", false);
|
|||
|
|
reviewer.put("activity.view", false);
|
|||
|
|
reviewer.put("activity.create", false);
|
|||
|
|
reviewer.put("activity.review_registration", false);
|
|||
|
|
reviewer.put("risk.report.view", false);
|
|||
|
|
reviewer.put("risk.report.process", false);
|
|||
|
|
reviewer.put("risk.user.ban", false);
|
|||
|
|
reviewer.put("organization.manage", false);
|
|||
|
|
reviewer.put("permission.manage", false);
|
|||
|
|
reviewer.put("analytics.view", false);
|
|||
|
|
reviewer.put("data.export", false);
|
|||
|
|
PERMISSION_MATRIX.put("reviewer", reviewer);
|
|||
|
|
|
|||
|
|
// matchmaker: 红娘服务
|
|||
|
|
Map<String, Boolean> matchmaker = new HashMap<>();
|
|||
|
|
matchmaker.put("user.view", true); // 服务必要
|
|||
|
|
matchmaker.put("user.sensitive.view", false);
|
|||
|
|
matchmaker.put("user.status.change", false);
|
|||
|
|
matchmaker.put("review.view", false);
|
|||
|
|
matchmaker.put("review.process", false);
|
|||
|
|
matchmaker.put("matchmaker.view", true);
|
|||
|
|
matchmaker.put("matchmaker.assign", false);
|
|||
|
|
matchmaker.put("matchmaker.service", true);
|
|||
|
|
matchmaker.put("activity.view", false);
|
|||
|
|
matchmaker.put("activity.create", false);
|
|||
|
|
matchmaker.put("activity.review_registration", false);
|
|||
|
|
matchmaker.put("risk.report.view", false);
|
|||
|
|
matchmaker.put("risk.report.process", false);
|
|||
|
|
matchmaker.put("risk.user.ban", false);
|
|||
|
|
matchmaker.put("organization.manage", false);
|
|||
|
|
matchmaker.put("permission.manage", false);
|
|||
|
|
matchmaker.put("analytics.view", false);
|
|||
|
|
matchmaker.put("data.export", false);
|
|||
|
|
PERMISSION_MATRIX.put("matchmaker", matchmaker);
|
|||
|
|
|
|||
|
|
// activity_manager: 活动管理
|
|||
|
|
Map<String, Boolean> activityManager = new HashMap<>();
|
|||
|
|
activityManager.put("user.view", true); // 活动必要
|
|||
|
|
activityManager.put("user.sensitive.view", false);
|
|||
|
|
activityManager.put("user.status.change", false);
|
|||
|
|
activityManager.put("review.view", false);
|
|||
|
|
activityManager.put("review.process", false);
|
|||
|
|
activityManager.put("matchmaker.view", false);
|
|||
|
|
activityManager.put("matchmaker.assign", false);
|
|||
|
|
activityManager.put("matchmaker.service", false);
|
|||
|
|
activityManager.put("activity.view", true);
|
|||
|
|
activityManager.put("activity.create", true);
|
|||
|
|
activityManager.put("activity.review_registration", true);
|
|||
|
|
activityManager.put("risk.report.view", false);
|
|||
|
|
activityManager.put("risk.report.process", false);
|
|||
|
|
activityManager.put("risk.user.ban", false);
|
|||
|
|
activityManager.put("organization.manage", false);
|
|||
|
|
activityManager.put("permission.manage", false);
|
|||
|
|
activityManager.put("analytics.view", false);
|
|||
|
|
activityManager.put("data.export", false);
|
|||
|
|
PERMISSION_MATRIX.put("activity_manager", activityManager);
|
|||
|
|
|
|||
|
|
// risk_operator: 风控
|
|||
|
|
Map<String, Boolean> riskOperator = new HashMap<>();
|
|||
|
|
riskOperator.put("user.view", true); // 案件必要
|
|||
|
|
riskOperator.put("user.sensitive.view", true); // 特殊
|
|||
|
|
riskOperator.put("user.status.change", false);
|
|||
|
|
riskOperator.put("review.view", false);
|
|||
|
|
riskOperator.put("review.process", false);
|
|||
|
|
riskOperator.put("matchmaker.view", false);
|
|||
|
|
riskOperator.put("matchmaker.assign", false);
|
|||
|
|
riskOperator.put("matchmaker.service", false);
|
|||
|
|
riskOperator.put("activity.view", false);
|
|||
|
|
riskOperator.put("activity.create", false);
|
|||
|
|
riskOperator.put("activity.review_registration", false);
|
|||
|
|
riskOperator.put("risk.report.view", true);
|
|||
|
|
riskOperator.put("risk.report.process", true);
|
|||
|
|
riskOperator.put("risk.user.ban", true);
|
|||
|
|
riskOperator.put("organization.manage", false);
|
|||
|
|
riskOperator.put("permission.manage", false);
|
|||
|
|
riskOperator.put("analytics.view", false);
|
|||
|
|
riskOperator.put("data.export", false);
|
|||
|
|
PERMISSION_MATRIX.put("risk_operator", riskOperator);
|
|||
|
|
|
|||
|
|
// volunteer: 最小权限
|
|||
|
|
Map<String, Boolean> volunteer = new HashMap<>();
|
|||
|
|
volunteer.put("user.view", false);
|
|||
|
|
volunteer.put("user.sensitive.view", false);
|
|||
|
|
volunteer.put("user.status.change", false);
|
|||
|
|
volunteer.put("review.view", false);
|
|||
|
|
volunteer.put("review.process", false);
|
|||
|
|
volunteer.put("matchmaker.view", false);
|
|||
|
|
volunteer.put("matchmaker.assign", false);
|
|||
|
|
volunteer.put("matchmaker.service", false);
|
|||
|
|
volunteer.put("activity.view", true); // 签到必要
|
|||
|
|
volunteer.put("activity.create", false);
|
|||
|
|
volunteer.put("activity.review_registration", false);
|
|||
|
|
volunteer.put("risk.report.view", false);
|
|||
|
|
volunteer.put("risk.report.process", false);
|
|||
|
|
volunteer.put("risk.user.ban", false);
|
|||
|
|
volunteer.put("organization.manage", false);
|
|||
|
|
volunteer.put("permission.manage", false);
|
|||
|
|
volunteer.put("analytics.view", false);
|
|||
|
|
volunteer.put("data.export", false);
|
|||
|
|
PERMISSION_MATRIX.put("volunteer", volunteer);
|
|||
|
|
|
|||
|
|
// data_viewer: 仅查看统计
|
|||
|
|
Map<String, Boolean> dataViewer = new HashMap<>();
|
|||
|
|
dataViewer.put("user.view", false);
|
|||
|
|
dataViewer.put("user.sensitive.view", false);
|
|||
|
|
dataViewer.put("user.status.change", false);
|
|||
|
|
dataViewer.put("review.view", false);
|
|||
|
|
dataViewer.put("review.process", false);
|
|||
|
|
dataViewer.put("matchmaker.view", false);
|
|||
|
|
dataViewer.put("matchmaker.assign", false);
|
|||
|
|
dataViewer.put("matchmaker.service", false);
|
|||
|
|
dataViewer.put("activity.view", false);
|
|||
|
|
dataViewer.put("activity.create", false);
|
|||
|
|
dataViewer.put("activity.review_registration", false);
|
|||
|
|
dataViewer.put("risk.report.view", false);
|
|||
|
|
dataViewer.put("risk.report.process", false);
|
|||
|
|
dataViewer.put("risk.user.ban", false);
|
|||
|
|
dataViewer.put("organization.manage", false);
|
|||
|
|
dataViewer.put("permission.manage", false);
|
|||
|
|
dataViewer.put("analytics.view", true);
|
|||
|
|
dataViewer.put("data.export", false);
|
|||
|
|
PERMISSION_MATRIX.put("data_viewer", dataViewer);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ==================== 权限矩阵测试 ====================
|
|||
|
|
|
|||
|
|
@Test
|
|||
|
|
void testSuperAdminHasMostPermissions() {
|
|||
|
|
long count = PERMISSION_MATRIX.get("super_admin").values().stream()
|
|||
|
|
.filter(Boolean::booleanValue).count();
|
|||
|
|
assertTrue(count >= 15, "super_admin应有至少15项权限,实际" + count);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
@Test
|
|||
|
|
void testVolunteerHasMinimalPermissions() {
|
|||
|
|
long count = PERMISSION_MATRIX.get("volunteer").values().stream()
|
|||
|
|
.filter(Boolean::booleanValue).count();
|
|||
|
|
assertEquals(1, count, "志愿者应仅有1项权限(activity.view)");
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
@Test
|
|||
|
|
void testDataViewerCannotAccessUserData() {
|
|||
|
|
assertFalse(PERMISSION_MATRIX.get("data_viewer").get("user.view"),
|
|||
|
|
"data_viewer不应有user.view权限");
|
|||
|
|
assertFalse(PERMISSION_MATRIX.get("data_viewer").get("user.sensitive.view"),
|
|||
|
|
"data_viewer不应有user.sensitive.view权限");
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
@Test
|
|||
|
|
void testReviewerCanOnlyReview() {
|
|||
|
|
long reviewCount = 0;
|
|||
|
|
for (Map.Entry<String, Boolean> e : PERMISSION_MATRIX.get("reviewer").entrySet()) {
|
|||
|
|
if (e.getValue()) reviewCount++;
|
|||
|
|
}
|
|||
|
|
assertEquals(2, reviewCount, "审核员应有且仅有review.view + review.process两项权限");
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
@Test
|
|||
|
|
void testRiskOperatorCannotManageOrganization() {
|
|||
|
|
assertFalse(PERMISSION_MATRIX.get("risk_operator").get("organization.manage"),
|
|||
|
|
"风控员不应有组织管理权限");
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
@Test
|
|||
|
|
void testMatchmakerCannotBanUsers() {
|
|||
|
|
assertFalse(PERMISSION_MATRIX.get("matchmaker").get("risk.user.ban"),
|
|||
|
|
"红娘不应有封禁用户权限");
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
@Test
|
|||
|
|
void testActivityManagerCannotProcessReports() {
|
|||
|
|
assertFalse(PERMISSION_MATRIX.get("activity_manager").get("risk.report.process"),
|
|||
|
|
"活动管理员不应有举报处理权限");
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
@Test
|
|||
|
|
void testNoRoleHasAllPermissions() {
|
|||
|
|
// 除super_admin外,没有任何角色拥有全部权限
|
|||
|
|
for (Map.Entry<String, Map<String, Boolean>> entry : PERMISSION_MATRIX.entrySet()) {
|
|||
|
|
if ("super_admin".equals(entry.getKey())) continue;
|
|||
|
|
long denied = entry.getValue().values().stream()
|
|||
|
|
.filter(v -> !v).count();
|
|||
|
|
assertTrue(denied >= 5,
|
|||
|
|
entry.getKey() + " 应有至少5个被拒绝的权限");
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
@Test
|
|||
|
|
void testSuperAdminCanDoEverything() {
|
|||
|
|
Map<String, Boolean> perms = PERMISSION_MATRIX.get("super_admin");
|
|||
|
|
long granted = perms.values().stream().filter(Boolean::booleanValue).count();
|
|||
|
|
assertEquals(perms.size(), granted, "super_admin应有全部权限");
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
@Test
|
|||
|
|
void testOrganizationAdminCannotManagePermissions() {
|
|||
|
|
assertFalse(PERMISSION_MATRIX.get("organization_admin").get("permission.manage"),
|
|||
|
|
"机构管理员不应有权限管理权限");
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
@Test
|
|||
|
|
void testAllRolesHaveUniquePermissionSets() {
|
|||
|
|
// 每个角色的权限集合应该不同(不能完全相同)
|
|||
|
|
Set<String> roleNames = PERMISSION_MATRIX.keySet();
|
|||
|
|
for (int i = 0; i < roleNames.size(); i++) {
|
|||
|
|
for (int j = i + 1; j < roleNames.size(); j++) {
|
|||
|
|
String r1 = new ArrayList<>(roleNames).get(i);
|
|||
|
|
String r2 = new ArrayList<>(roleNames).get(j);
|
|||
|
|
// 两个不同角色的权限不完全相同
|
|||
|
|
boolean different = false;
|
|||
|
|
for (String perm : PERMISSION_MATRIX.get(r1).keySet()) {
|
|||
|
|
if (!PERMISSION_MATRIX.get(r1).get(perm).equals(
|
|||
|
|
PERMISSION_MATRIX.get(r2).get(perm))) {
|
|||
|
|
different = true;
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
assertTrue(different, r1 + " 和 " + r2 + " 的权限集应不同");
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ==================== 与数据库权限码对照 ====================
|
|||
|
|
|
|||
|
|
@Test
|
|||
|
|
void testAllDefinedPermissionsExistInCodebase() {
|
|||
|
|
// 验证权限矩阵中定义的权限码都在 permissions 表中有所对应
|
|||
|
|
String[] expectedCodes = {
|
|||
|
|
"user.view", "user.sensitive.view", "user.status.change",
|
|||
|
|
"review.view", "review.process",
|
|||
|
|
"matchmaker.view", "matchmaker.assign", "matchmaker.service",
|
|||
|
|
"activity.view", "activity.create", "activity.review_registration",
|
|||
|
|
"risk.report.view", "risk.report.process", "risk.user.ban",
|
|||
|
|
"organization.manage", "permission.manage",
|
|||
|
|
"analytics.view", "data.export"
|
|||
|
|
};
|
|||
|
|
assertEquals(18, expectedCodes.length, "权限码数量应与定义一致");
|
|||
|
|
}
|
|||
|
|
}
|