statistics-permission-test.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327
  1. /**
  2. * 统计卡片权限测试脚本
  3. * 功能:验证统计卡片区域的权限控制是否正确
  4. * 时间:2025-06-30 18:55:00
  5. */
  6. const axios = require('axios');
  7. const colors = require('colors');
  8. // 测试配置
  9. const config = {
  10. baseURL: 'http://localhost/dev-api',
  11. timeout: 10000,
  12. testAccounts: [
  13. { username: 'admin', password: 'admin123', role: 'superadmin', expectVisible: true },
  14. {
  15. username: 'property_admin_test',
  16. password: 'admin123',
  17. role: 'property_maintenance_admin',
  18. expectVisible: true,
  19. },
  20. {
  21. username: 'maintenance_test',
  22. password: 'admin123',
  23. role: 'maintenance_worker',
  24. expectVisible: false,
  25. },
  26. ],
  27. };
  28. /**
  29. * AES+RSA双重加密登录
  30. */
  31. async function encryptedLogin(username, password) {
  32. const CryptoJS = require('crypto-js');
  33. const NodeRSA = require('node-rsa');
  34. // 配置信息
  35. const rsaKey =
  36. 'MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKoR8mX0rGKLqzcWmOzbfj64K8ZIgOdHnzkXSOVOZbFu/TJhZ7rFAN+eaGkl3C4buccQd/EjEsj9ir7ijT7h96MCAwEAAQ==';
  37. const clientId = 'e5cd7e4891bf95d1d19206ce24a7b32e';
  38. // 生成32位随机AES密钥
  39. function generateAESKey() {
  40. const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
  41. let result = '';
  42. for (let i = 0; i < 32; i++) {
  43. result += chars.charAt(Math.floor(Math.random() * chars.length));
  44. }
  45. return result;
  46. }
  47. // AES加密
  48. function aesEncrypt(data, key) {
  49. const keyUtf8 = CryptoJS.enc.Utf8.parse(key);
  50. return CryptoJS.AES.encrypt(data, keyUtf8, {
  51. mode: CryptoJS.mode.ECB,
  52. padding: CryptoJS.pad.Pkcs7,
  53. }).toString();
  54. }
  55. // RSA加密AES密钥
  56. function rsaEncrypt(aesKey) {
  57. const pemKey = `-----BEGIN PUBLIC KEY-----\n${rsaKey}\n-----END PUBLIC KEY-----`;
  58. const rsaKey_obj = new NodeRSA(pemKey);
  59. rsaKey_obj.setOptions({ encryptionScheme: 'pkcs1' });
  60. const aesKeyBase64 = CryptoJS.enc.Base64.stringify(CryptoJS.enc.Utf8.parse(aesKey));
  61. return rsaKey_obj.encrypt(aesKeyBase64, 'base64');
  62. }
  63. // 生成AES密钥并加密登录数据
  64. const aesKey = generateAESKey();
  65. const loginData = {
  66. tenantId: '000000',
  67. username: username,
  68. password: password,
  69. clientId: clientId,
  70. grantType: 'password',
  71. };
  72. const encryptedData = aesEncrypt(JSON.stringify(loginData), aesKey);
  73. const encryptedKey = rsaEncrypt(aesKey);
  74. // 设置请求头
  75. const headers = {
  76. 'Content-Type': 'application/json;charset=utf-8',
  77. clientid: clientId,
  78. 'encrypt-key': encryptedKey,
  79. referer: 'http://localhost/login?redirect=%252Findex',
  80. 'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8',
  81. isToken: 'false',
  82. isEncrypt: 'true',
  83. repeatSubmit: 'false',
  84. };
  85. try {
  86. const response = await axios.post(`${config.baseURL}/auth/login`, encryptedData, {
  87. headers: headers,
  88. timeout: config.timeout,
  89. });
  90. if (response.data.code === 200 && response.data.data?.access_token) {
  91. return response.data.data.access_token;
  92. } else {
  93. throw new Error(response.data.msg || 'Login failed');
  94. }
  95. } catch (error) {
  96. throw new Error(`登录失败: ${error.message}`);
  97. }
  98. }
  99. /**
  100. * 获取用户信息
  101. */
  102. async function getUserInfo(token) {
  103. try {
  104. const response = await axios.get(`${config.baseURL}/system/user/getInfo`, {
  105. headers: {
  106. Authorization: `Bearer ${token}`,
  107. clientid: 'e5cd7e4891bf95d1d19206ce24a7b32e',
  108. 'Content-Type': 'application/json;charset=utf-8',
  109. },
  110. timeout: config.timeout,
  111. });
  112. if (response.data.code === 200) {
  113. return response.data.data;
  114. } else {
  115. throw new Error(response.data.msg || 'Get user info failed');
  116. }
  117. } catch (error) {
  118. throw new Error(`获取用户信息失败: ${error.message}`);
  119. }
  120. }
  121. /**
  122. * 获取统计数据(验证接口权限)
  123. */
  124. async function getStatistics(token) {
  125. try {
  126. const response = await axios.get(`${config.baseURL}/pm/repairOrder/statistics`, {
  127. headers: {
  128. Authorization: `Bearer ${token}`,
  129. clientid: 'e5cd7e4891bf95d1d19206ce24a7b32e',
  130. 'Content-Type': 'application/json;charset=utf-8',
  131. },
  132. timeout: config.timeout,
  133. });
  134. return {
  135. success: response.data.code === 200,
  136. data: response.data.data,
  137. message: response.data.msg,
  138. };
  139. } catch (error) {
  140. return {
  141. success: false,
  142. data: null,
  143. message: error.response?.data?.msg || error.message,
  144. };
  145. }
  146. }
  147. /**
  148. * 检查用户角色权限
  149. */
  150. function checkStatisticsPermission(userInfo) {
  151. if (!userInfo || !userInfo.roles) {
  152. return false;
  153. }
  154. // 检查是否为超级管理员
  155. if (userInfo.admin) {
  156. return true;
  157. }
  158. // 检查是否为物业维修管理员
  159. const roles = userInfo.roles || [];
  160. return roles.some((role) => role.roleKey === 'property_maintenance_admin');
  161. }
  162. /**
  163. * 执行权限测试
  164. */
  165. async function testStatisticsPermissions() {
  166. console.log(colors.cyan('='.repeat(80)));
  167. console.log(colors.cyan('统计卡片权限测试开始'));
  168. console.log(colors.cyan('='.repeat(80)));
  169. const results = [];
  170. for (const account of config.testAccounts) {
  171. console.log(colors.yellow(`\n正在测试账号: ${account.username} (${account.role})`));
  172. try {
  173. // 登录获取Token
  174. console.log(' ├─ 正在登录...');
  175. const token = await encryptedLogin(account.username, account.password);
  176. console.log(' ├─ 登录成功 ✓');
  177. // 获取用户信息
  178. console.log(' ├─ 获取用户信息...');
  179. const userInfo = await getUserInfo(token);
  180. console.log(' ├─ 用户信息获取成功 ✓');
  181. // 检查前端权限逻辑
  182. const frontendPermission = checkStatisticsPermission(userInfo);
  183. console.log(
  184. ` ├─ 前端权限检查: ${frontendPermission ? '有权限' : '无权限'} ${
  185. frontendPermission === account.expectVisible ? '✓' : '✗'
  186. }`,
  187. );
  188. // 测试后端统计接口
  189. console.log(' ├─ 测试统计接口...');
  190. const statsResult = await getStatistics(token);
  191. console.log(
  192. ` ├─ 统计接口调用: ${statsResult.success ? '成功' : '失败'} ${
  193. statsResult.success === account.expectVisible ? '✓' : '✗'
  194. }`,
  195. );
  196. const testResult = {
  197. username: account.username,
  198. role: account.role,
  199. expectedVisible: account.expectVisible,
  200. frontendPermission: frontendPermission,
  201. backendPermission: statsResult.success,
  202. frontendCorrect: frontendPermission === account.expectVisible,
  203. backendCorrect: statsResult.success === account.expectVisible,
  204. message: statsResult.message,
  205. };
  206. results.push(testResult);
  207. if (testResult.frontendCorrect && testResult.backendCorrect) {
  208. console.log(' └─ 测试结果: ' + colors.green('通过 ✓'));
  209. } else {
  210. console.log(' └─ 测试结果: ' + colors.red('失败 ✗'));
  211. }
  212. } catch (error) {
  213. console.log(' └─ 测试结果: ' + colors.red(`错误 - ${error.message}`));
  214. results.push({
  215. username: account.username,
  216. role: account.role,
  217. expectedVisible: account.expectVisible,
  218. frontendPermission: false,
  219. backendPermission: false,
  220. frontendCorrect: false,
  221. backendCorrect: false,
  222. message: error.message,
  223. });
  224. }
  225. }
  226. // 输出测试结果汇总
  227. console.log(colors.cyan('\n='.repeat(80)));
  228. console.log(colors.cyan('测试结果汇总'));
  229. console.log(colors.cyan('='.repeat(80)));
  230. console.log('\n账号权限测试结果:');
  231. console.log(
  232. '┌─────────────────────┬──────────────────────┬──────────────┬──────────────┬──────┐',
  233. );
  234. console.log(
  235. '│ 账号 │ 角色 │ 前端权限 │ 后端权限 │ 状态 │',
  236. );
  237. console.log(
  238. '├─────────────────────┼──────────────────────┼──────────────┼──────────────┼──────┤',
  239. );
  240. let allTestsPassed = true;
  241. for (const result of results) {
  242. const username = result.username.padEnd(17);
  243. const role = result.role.padEnd(18);
  244. const frontend = (result.frontendPermission ? '有权限' : '无权限').padEnd(10);
  245. const backend = (result.backendPermission ? '有权限' : '无权限').padEnd(10);
  246. const status = result.frontendCorrect && result.backendCorrect ? '✓ 通过' : '✗ 失败';
  247. const statusColor =
  248. result.frontendCorrect && result.backendCorrect ? colors.green : colors.red;
  249. console.log(
  250. `│ ${username} │ ${role} │ ${frontend} │ ${backend} │ ${statusColor(status)} │`,
  251. );
  252. if (!result.frontendCorrect || !result.backendCorrect) {
  253. allTestsPassed = false;
  254. }
  255. }
  256. console.log(
  257. '└─────────────────────┴──────────────────────┴──────────────┴──────────────┴──────┘',
  258. );
  259. // 测试总结
  260. console.log(colors.cyan('\n测试总结:'));
  261. if (allTestsPassed) {
  262. console.log(colors.green('✓ 所有权限测试均通过!统计卡片权限控制正确实现。'));
  263. console.log(colors.green(' - 超级管理员和物业维修管理员可以访问统计功能'));
  264. console.log(colors.green(' - 维修人员和其他角色无法访问统计功能'));
  265. } else {
  266. console.log(colors.red('✗ 部分权限测试失败,请检查权限配置!'));
  267. // 输出失败的测试详情
  268. const failedTests = results.filter((r) => !r.frontendCorrect || !r.backendCorrect);
  269. for (const failed of failedTests) {
  270. console.log(colors.red(` - ${failed.username}: ${failed.message}`));
  271. }
  272. }
  273. console.log(colors.cyan('\n='.repeat(80)));
  274. }
  275. /**
  276. * 主函数
  277. */
  278. async function main() {
  279. try {
  280. await testStatisticsPermissions();
  281. } catch (error) {
  282. console.error(colors.red('测试执行失败:'), error.message);
  283. process.exit(1);
  284. }
  285. }
  286. // 运行测试
  287. main().catch(console.error);