Files
hzdyjs/test/repair-order-data-permission-test.js
T
2025-06-30 20:33:58 +08:00

409 lines
14 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
const axios = require('axios');
const colors = require('colors');
// 配置信息
const CONFIG = {
baseURL: 'http://localhost/dev-api',
timeout: 10000,
};
// 测试用户配置
const TEST_USERS = {
// 超级管理员
superAdmin: {
username: 'admin',
password: 'admin123',
description: '超级管理员',
expectedRole: 'superadmin',
},
// 物业维修管理员
propertyAdmin: {
username: 'zwc003', // 总务处科长舒刚
password: 'admin123',
description: '物业维修管理员',
expectedRole: 'property_maintenance_admin',
},
// 维修人员
maintenanceWorker: {
username: 'zwc005', // 总务处干事陆雄
password: 'admin123',
description: '维修人员',
expectedRole: 'maintenance_worker',
},
// 普通用户
normalUser: {
username: 'zkxy001', // 智控学院张三
password: 'admin123',
description: '普通用户(报修人)',
expectedRole: 'none',
},
};
/**
* 登录获取Token
*/
async function login(username, password) {
const CryptoJS = require('crypto-js');
const NodeRSA = require('node-rsa');
// 生成32位随机AES密钥
function generateAESKey() {
const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
let result = '';
for (let i = 0; i < 32; i++) {
result += chars.charAt(Math.floor(Math.random() * chars.length));
}
return result;
}
// AES加密
function aesEncrypt(data, key) {
const keyUtf8 = CryptoJS.enc.Utf8.parse(key);
return CryptoJS.AES.encrypt(data, keyUtf8, {
mode: CryptoJS.mode.ECB,
padding: CryptoJS.pad.Pkcs7,
}).toString();
}
// RSA加密AES密钥
function rsaEncrypt(aesKey) {
const rsaKeyStr =
'MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKoR8mX0rGKLqzcWmOzbfj64K8ZIgOdHnzkXSOVOZbFu/TJhZ7rFAN+eaGkl3C4buccQd/EjEsj9ir7ijT7h96MCAwEAAQ==';
const pemKey = `-----BEGIN PUBLIC KEY-----\n${rsaKeyStr}\n-----END PUBLIC KEY-----`;
const rsaKey = new NodeRSA(pemKey);
rsaKey.setOptions({ encryptionScheme: 'pkcs1' });
const aesKeyBase64 = CryptoJS.enc.Base64.stringify(CryptoJS.enc.Utf8.parse(aesKey));
return rsaKey.encrypt(aesKeyBase64, 'base64');
}
const aesKey = generateAESKey();
const loginData = {
tenantId: '000000',
username: username,
password: password,
clientId: 'e5cd7e4891bf95d1d19206ce24a7b32e',
grantType: 'password',
};
const encryptedData = aesEncrypt(JSON.stringify(loginData), aesKey);
const encryptedKey = rsaEncrypt(aesKey);
const headers = {
'Content-Type': 'application/json;charset=utf-8',
clientid: 'e5cd7e4891bf95d1d19206ce24a7b32e',
'encrypt-key': encryptedKey,
referer: 'http://localhost/login?redirect=%252Findex',
'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8',
isToken: 'false',
isEncrypt: 'true',
};
try {
const response = await axios.post(`${CONFIG.baseURL}/auth/login`, encryptedData, {
headers: headers,
timeout: CONFIG.timeout,
});
if (response.data.code === 200 && response.data.data?.access_token) {
return response.data.data.access_token;
} else {
throw new Error(response.data.msg || 'Login failed');
}
} catch (error) {
console.error(`登录失败 [${username}]:`, error.message);
throw error;
}
}
/**
* 调用API接口
*/
async function callAPI(token, endpoint, method = 'GET', data = null) {
try {
const config = {
method: method.toLowerCase(),
url: `${CONFIG.baseURL}${endpoint}`,
headers: {
'Content-Type': 'application/json;charset=utf-8',
Authorization: `Bearer ${token}`,
clientid: 'e5cd7e4891bf95d1d19206ce24a7b32e',
'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8',
referer: 'http://localhost/login?redirect=%252Findex',
},
timeout: CONFIG.timeout,
};
if (data && method.toUpperCase() !== 'GET') {
config.data = data;
} else if (data && method.toUpperCase() === 'GET') {
config.params = data;
}
const response = await axios(config);
return {
success: true,
data: response.data,
status: response.status,
};
} catch (error) {
return {
success: false,
error: error.response?.data || error.message,
status: error.response?.status || 0,
};
}
}
/**
* 获取用户信息
*/
async function getUserInfo(token) {
return await callAPI(token, '/system/user/getInfo');
}
/**
* 获取报修工单列表
*/
async function getRepairOrders(token, params = {}) {
return await callAPI(token, '/pm/repairOrder/list', 'GET', params);
}
/**
* 获取指定工单详情
*/
async function getRepairOrderDetail(token, orderId) {
return await callAPI(token, `/pm/repairOrder/${orderId}`);
}
/**
* 测试数据权限
*/
async function testDataPermissions() {
console.log('🔐 报修工单数据权限测试'.yellow.bold);
console.log('='.repeat(80).gray);
const results = {};
for (const [userType, userConfig] of Object.entries(TEST_USERS)) {
console.log(`\n📋 测试用户:${userConfig.description} (${userConfig.username})`.cyan.bold);
console.log('-'.repeat(60).gray);
try {
// 1. 登录获取Token
console.log('🔑 正在登录...'.yellow);
const token = await login(userConfig.username, userConfig.password);
console.log('✅ 登录成功'.green);
// 2. 获取用户信息
console.log('👤 获取用户信息...'.yellow);
const userInfoResult = await getUserInfo(token);
if (userInfoResult.success) {
const userInfo = userInfoResult.data.data;
console.log(
`✅ 用户信息:${userInfo.user.nickName} | 角色:${userInfo.roles.join(', ')}`,
);
results[userType] = {
userConfig,
userInfo: userInfo,
token,
tests: {},
};
} else {
console.log('❌ 获取用户信息失败'.red);
continue;
}
// 3. 测试工单列表权限
console.log('📝 测试工单列表权限...'.yellow);
const listResult = await getRepairOrders(token);
if (listResult.success) {
const totalOrders = listResult.data.total || 0;
const orders = listResult.data.rows || [];
console.log(`✅ 可查看工单数量:${totalOrders} 个`);
results[userType].tests.listAccess = {
success: true,
totalOrders,
orders: orders.slice(0, 3), // 只保存前3个用于显示
};
// 显示可查看的工单概况
if (orders.length > 0) {
console.log(' 可查看的工单:');
orders.slice(0, 3).forEach((order) => {
console.log(
` - ${order.orderNo}: ${order.title} (报修人:${
order.reporterName
}, 维修员:${order.assigneeName || '未分派'})`,
);
});
if (orders.length > 3) {
console.log(` - 还有 ${orders.length - 3} 个工单...`);
}
}
} else {
console.log(`❌ 工单列表查询失败:${listResult.error.msg || listResult.error}`);
results[userType].tests.listAccess = {
success: false,
error: listResult.error,
};
}
// 4. 测试具体工单详情权限(测试工单ID: 1001, 1002, 1003)
console.log('🔍 测试工单详情权限...'.yellow);
const testOrderIds = [1001, 1002, 1003];
const detailResults = [];
for (const orderId of testOrderIds) {
const detailResult = await getRepairOrderDetail(token, orderId);
if (detailResult.success) {
const order = detailResult.data.data;
console.log(` ✅ 工单 ${orderId}: ${order.title} (有权限查看)`);
detailResults.push({
orderId,
success: true,
order: {
orderNo: order.orderNo,
title: order.title,
reporterName: order.reporterName,
assigneeName: order.assigneeName,
},
});
} else {
console.log(
` ❌ 工单 ${orderId}: 无权限查看 (${
detailResult.error.msg || detailResult.error
})`,
);
detailResults.push({
orderId,
success: false,
error: detailResult.error.msg || detailResult.error,
});
}
}
results[userType].tests.detailAccess = detailResults;
} catch (error) {
console.log(`❌ 测试失败:${error.message}`.red);
results[userType] = {
userConfig,
error: error.message,
};
}
}
// 输出测试总结
console.log('\n📊 数据权限测试总结'.cyan.bold);
console.log('='.repeat(80).gray);
for (const [userType, result] of Object.entries(results)) {
if (result.error) {
console.log(`❌ ${result.userConfig.description}: 测试失败 - ${result.error}`.red);
continue;
}
const listAccess = result.tests.listAccess;
const detailAccess = result.tests.detailAccess;
console.log(`\n👤 ${result.userConfig.description} (${result.userConfig.username}):`.cyan);
console.log(` 角色权限:${result.userInfo.roles.join(', ')}`);
console.log(
` 可查看工单:${listAccess.success ? listAccess.totalOrders + ' 个' : '查询失败'}`,
);
if (detailAccess) {
const accessibleDetails = detailAccess.filter((d) => d.success).length;
console.log(
` 详情权限:${accessibleDetails}/${detailAccess.length} 个工单可查看详情`,
);
}
}
// 权限验证结果
console.log('\n🎯 权限验证结果'.green.bold);
console.log('-'.repeat(60).gray);
// 验证超级管理员权限
const superAdminResult = results.superAdmin;
if (superAdminResult && !superAdminResult.error) {
const canViewAll = superAdminResult.tests.listAccess.totalOrders >= 12; // 应该能看到所有工单
console.log(
`✅ 超级管理员权限:${canViewAll ? '✅ 正确' : '❌ 异常'} (可查看 ${
superAdminResult.tests.listAccess.totalOrders
} 个工单)`,
);
}
// 验证物业维修管理员权限
const propertyAdminResult = results.propertyAdmin;
if (propertyAdminResult && !propertyAdminResult.error) {
const canViewAll = propertyAdminResult.tests.listAccess.totalOrders >= 12; // 应该能看到所有工单
console.log(
`✅ 物业维修管理员权限:${canViewAll ? '✅ 正确' : '❌ 异常'} (可查看 ${
propertyAdminResult.tests.listAccess.totalOrders
} 个工单)`,
);
}
// 验证维修人员权限
const workerResult = results.maintenanceWorker;
if (workerResult && !workerResult.error) {
const limitedAccess = workerResult.tests.listAccess.totalOrders < 12; // 应该只能看到部分工单
console.log(
`✅ 维修人员权限:${limitedAccess ? '✅ 正确' : '❌ 异常'} (可查看 ${
workerResult.tests.listAccess.totalOrders
} 个工单)`,
);
}
// 验证普通用户权限
const normalUserResult = results.normalUser;
if (normalUserResult && !normalUserResult.error) {
const limitedAccess = normalUserResult.tests.listAccess.totalOrders <= 2; // 应该只能看到自己的工单
console.log(
`✅ 普通用户权限:${limitedAccess ? '✅ 正确' : '❌ 异常'} (可查看 ${
normalUserResult.tests.listAccess.totalOrders
} 个工单)`,
);
}
return results;
}
/**
* 主函数
*/
async function main() {
try {
console.log('🚀 开始数据权限测试...'.green.bold);
const results = await testDataPermissions();
console.log('\n✅ 数据权限测试完成!'.green.bold);
// 保存测试结果到文件(可选)
const fs = require('fs');
const reportPath = `data-permission-test-result-${
new Date().toISOString().split('T')[0]
}.json`;
fs.writeFileSync(reportPath, JSON.stringify(results, null, 2));
console.log(`📋 测试结果已保存到:${reportPath}`.gray);
} catch (error) {
console.error('❌ 测试执行失败:', error.message.red);
process.exit(1);
}
}
// 运行测试
if (require.main === module) {
main();
}
module.exports = {
testDataPermissions,
login,
callAPI,
TEST_USERS,
};