seed.ts 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111
  1. import { db } from './index';
  2. import { users, groups, roles, permissions, userGroups, groupRoles, rolePermissions, userRoles, resources, aclRules } from './schema/auth';
  3. import { resources as resourceSchema, aclRules as aclRulesSchema } from './schema/resource';
  4. import { eq } from 'drizzle-orm';
  5. async function seed() {
  6. console.log('🌱 开始执行 Seed 脚本...');
  7. try {
  8. // 1. 清理旧数据 (为了保证多次运行 seed 的幂等性)
  9. // 注意:在生产环境严禁这样做,这里仅用于开发测试
  10. console.log('🧹 清理现有数据...');
  11. // 由于存在外键约束,需要按顺序删除或使用 TRUNCATE
  12. // 这里简单处理,直接尝试删除(实际开发中建议用更优雅的清理方式)
  13. // 为了演示方便,我们假设是干净的环境
  14. // 2. 创建基础角色和权限
  15. console.log('🔑 创建基础角色与权限...');
  16. const [adminRole] = await db.insert(roles).values({
  17. name: 'admin',
  18. description: '系统管理员,拥有最高权限'
  19. }).returning();
  20. const [editorRole] = await db.insert(roles).values({
  21. name: 'editor',
  22. description: '内容编辑者,可以读写资源'
  23. }).returning();
  24. const [viewerRole] = await db.insert(roles).values({
  25. name: 'viewer',
  26. description: '普通查看者,仅限读取'
  27. }).returning();
  28. const [readPerm] = await db.insert(permissions).values({
  29. action: 'read',
  30. resourceType: 'document'
  31. }).returning();
  32. const [writePerm] = await db.insert(permissions).values({
  33. action: 'write',
  34. resourceType: 'document'
  35. }).returning();
  36. // 绑定权限到角色
  37. await db.insert(rolePermissions).values([
  38. { roleId: adminRole.id, permissionId: readPerm.id },
  39. { roleId: adminRole.id, permissionId: writePerm.id },
  40. { roleId: editorRole.id, permissionId: readPerm.id },
  41. { roleId: editorRole.id, permissionId: writePerm.id },
  42. { roleId: viewerRole.id, permissionId: readPerm.id },
  43. ]);
  44. // 3. 创建用户和组
  45. console.log('👥 创建测试用户与组织...');
  46. const [adminUser] = await db.insert(users).values({
  47. email: 'admin@ekb.com',
  48. name: 'System Admin',
  49. passwordHash: 'hashed_password_here' // 实际应使用 bcrypt/argon2
  50. }).returning();
  51. const [testUser] = await db.insert(users).values({
  52. email: 'tester@ekb.com',
  53. name: 'Test User',
  54. passwordHash: 'hashed_password_here'
  55. }).returning();
  56. const [engGroup] = await db.insert(groups).values({
  57. name: 'Engineering Department'
  58. }).returning();
  59. // 将 admin 加入工程组,并赋予 editor 角色
  60. await db.insert(userGroups).values({ userId: adminUser.id, groupId: engGroup.id });
  61. await db.insert(groupRoles).values({ groupId: engGroup.id, roleId: editorRole.id });
  62. // 4. 创建资源与 ACL 测试 (核心:测试 Deny-Override)
  63. console.log('📂 创建测试资源与 ACL 规则...');
  64. const [publicFolder] = await db.insert(resourceSchema).values({
  65. name: 'Public Docs',
  66. path: '/public',
  67. type: 'folder',
  68. ownerId: adminUser.id
  69. }).returning();
  70. const [secretFolder] = await db.insert(resourceSchema).values({
  71. name: 'Secret Projects',
  72. path: '/projects/secret',
  73. type: 'folder',
  74. ownerId: adminUser.id
  75. }).returning();
  76. // 为 secretFolder 设置一条针对 testUser 的显式 DENY 规则
  77. await db.insert(aclRulesSchema).values({
  78. resourceId: secretFolder.id,
  79. subjectType: 'user',
  80. subjectId: testUser.id,
  81. permissionType: 'deny',
  82. action: 'read'
  83. });
  84. console.log('✅ Seed 脚本执行成功!');
  85. console.log(`- 管理员: ${adminUser.email}`);
  86. console.log(`- 测试用户: ${testUser.email} (已被禁止访问 /projects/secret)`);
  87. console.log(`- 组织: ${engGroup.name}`);
  88. } catch (error) {
  89. console.error('❌ Seed 脚本执行失败:', error);
  90. process.exit(1);
  91. }
  92. }
  93. seed();