- Change all permission codes from colon (`:`) to dot (`.`) separator to match handler require_permission() calls consistently - Add missing user.list, role.list, permission.list, organization.list, department.list, position.list permissions (handlers check for .list but seeds only had :read) - Add missing message module permissions (message.list, message.send, message.template.list, message.template.create) - Add missing setting.delete, numbering.delete permissions - Fix workflow handlers: workflow: → workflow. - Fix message handlers: message: → message. - Update viewer role READ_PERM_INDICES for new permission list This fixes a critical runtime bug where ALL permission checks in erp-auth and erp-config handlers would return 403 Forbidden because the seed data used colon separators but handlers checked for dots.
267 lines
12 KiB
Rust
267 lines
12 KiB
Rust
use sea_orm::{ActiveModelTrait, Set};
|
|
use uuid::Uuid;
|
|
|
|
use crate::entity::{permission, role, role_permission, user, user_credential, user_role};
|
|
use crate::error::AuthError;
|
|
|
|
use super::password;
|
|
|
|
/// Permission definitions to seed for every new tenant.
|
|
/// Each tuple is: (code, name, resource, action, description)
|
|
///
|
|
/// 编码使用点分隔 (`resource.action`),与 handler 中的 `require_permission` 调用保持一致。
|
|
const DEFAULT_PERMISSIONS: &[(&str, &str, &str, &str, &str)] = &[
|
|
// === Auth module ===
|
|
("user.list", "查看用户列表", "user", "list", "查看用户列表"),
|
|
("user.create", "创建用户", "user", "create", "创建新用户"),
|
|
("user.read", "查看用户详情", "user", "read", "查看用户信息"),
|
|
("user.update", "编辑用户", "user", "update", "编辑用户信息"),
|
|
("user.delete", "删除用户", "user", "delete", "软删除用户"),
|
|
("role.list", "查看角色列表", "role", "list", "查看角色列表"),
|
|
("role.create", "创建角色", "role", "create", "创建新角色"),
|
|
("role.read", "查看角色详情", "role", "read", "查看角色信息"),
|
|
("role.update", "编辑角色", "role", "update", "编辑角色"),
|
|
("role.delete", "删除角色", "role", "delete", "删除角色"),
|
|
("permission.list", "查看权限", "permission", "list", "查看权限列表"),
|
|
("organization.list", "查看组织列表", "organization", "list", "查看组织列表"),
|
|
("organization.create", "创建组织", "organization", "create", "创建组织"),
|
|
("organization.update", "编辑组织", "organization", "update", "编辑组织"),
|
|
("organization.delete", "删除组织", "organization", "delete", "删除组织"),
|
|
("department.list", "查看部门列表", "department", "list", "查看部门列表"),
|
|
("department.create", "创建部门", "department", "create", "创建部门"),
|
|
("department.update", "编辑部门", "department", "update", "编辑部门"),
|
|
("department.delete", "删除部门", "department", "delete", "删除部门"),
|
|
("position.list", "查看岗位列表", "position", "list", "查看岗位列表"),
|
|
("position.create", "创建岗位", "position", "create", "创建岗位"),
|
|
("position.update", "编辑岗位", "position", "update", "编辑岗位"),
|
|
("position.delete", "删除岗位", "position", "delete", "删除岗位"),
|
|
// === Config module ===
|
|
("dictionary.list", "查看字典", "dictionary", "list", "查看数据字典"),
|
|
("dictionary.create", "创建字典", "dictionary", "create", "创建数据字典"),
|
|
("dictionary.update", "编辑字典", "dictionary", "update", "编辑数据字典"),
|
|
("dictionary.delete", "删除字典", "dictionary", "delete", "删除数据字典"),
|
|
("menu.list", "查看菜单", "menu", "list", "查看菜单配置"),
|
|
("menu.update", "编辑菜单", "menu", "update", "编辑菜单配置"),
|
|
("setting.read", "查看配置", "setting", "read", "查看系统参数"),
|
|
("setting.update", "编辑配置", "setting", "update", "编辑系统参数"),
|
|
("setting.delete", "删除配置", "setting", "delete", "删除系统参数"),
|
|
("numbering.list", "查看编号规则", "numbering", "list", "查看编号规则"),
|
|
("numbering.create", "创建编号规则", "numbering", "create", "创建编号规则"),
|
|
("numbering.update", "编辑编号规则", "numbering", "update", "编辑编号规则"),
|
|
("numbering.delete", "删除编号规则", "numbering", "delete", "删除编号规则"),
|
|
("numbering.generate", "生成编号", "numbering", "generate", "生成文档编号"),
|
|
("theme.read", "查看主题", "theme", "read", "查看主题设置"),
|
|
("theme.update", "编辑主题", "theme", "update", "编辑主题设置"),
|
|
("language.list", "查看语言", "language", "list", "查看语言配置"),
|
|
("language.update", "编辑语言", "language", "update", "编辑语言设置"),
|
|
// === Workflow module ===
|
|
("workflow.create", "创建流程", "workflow", "create", "创建流程定义"),
|
|
("workflow.list", "查看流程", "workflow", "list", "查看流程列表"),
|
|
("workflow.read", "查看流程详情", "workflow", "read", "查看流程定义详情"),
|
|
("workflow.update", "编辑流程", "workflow", "update", "编辑流程定义"),
|
|
("workflow.publish", "发布流程", "workflow", "publish", "发布流程定义"),
|
|
("workflow.start", "发起流程", "workflow", "start", "发起流程实例"),
|
|
("workflow.approve", "审批任务", "workflow", "approve", "审批流程任务"),
|
|
("workflow.delegate", "委派任务", "workflow", "delegate", "委派流程任务"),
|
|
// === Message module ===
|
|
("message.list", "查看消息", "message", "list", "查看消息列表"),
|
|
("message.send", "发送消息", "message", "send", "发送新消息"),
|
|
("message.template.list", "查看消息模板", "message.template", "list", "查看消息模板列表"),
|
|
("message.template.create", "创建消息模板", "message.template", "create", "创建消息模板"),
|
|
];
|
|
|
|
/// Indices of read-only (list/read) permissions within DEFAULT_PERMISSIONS.
|
|
const READ_PERM_INDICES: &[usize] = &[
|
|
0, // user.list
|
|
2, // user.read
|
|
5, // role.list
|
|
7, // role.read
|
|
10, // permission.list
|
|
11, // organization.list
|
|
15, // department.list
|
|
19, // position.list
|
|
23, // dictionary.list
|
|
28, // menu.list
|
|
30, // setting.read
|
|
32, // numbering.list
|
|
37, // theme.read
|
|
39, // language.list
|
|
43, // workflow.list
|
|
44, // workflow.read
|
|
49, // message.list
|
|
51, // message.template.list
|
|
];
|
|
|
|
/// Seed default auth data for a new tenant.
|
|
///
|
|
/// Creates:
|
|
/// - 53 permissions covering auth/config/workflow/message modules
|
|
/// - An "admin" system role with all permissions
|
|
/// - A "viewer" system role with read-only permissions
|
|
/// - A super-admin user with the admin role and a password credential
|
|
pub async fn seed_tenant_auth(
|
|
db: &sea_orm::DatabaseConnection,
|
|
tenant_id: Uuid,
|
|
super_admin_password: &str,
|
|
) -> Result<(), AuthError> {
|
|
let now = chrono::Utc::now();
|
|
let system_user_id = Uuid::nil();
|
|
|
|
// 1. Create permissions
|
|
let mut perm_ids: Vec<Uuid> = Vec::with_capacity(DEFAULT_PERMISSIONS.len());
|
|
for (code, name, resource, action, desc) in DEFAULT_PERMISSIONS {
|
|
let perm_id = Uuid::now_v7();
|
|
perm_ids.push(perm_id);
|
|
|
|
let perm = permission::ActiveModel {
|
|
id: Set(perm_id),
|
|
tenant_id: Set(tenant_id),
|
|
code: Set(code.to_string()),
|
|
name: Set(name.to_string()),
|
|
resource: Set(resource.to_string()),
|
|
action: Set(action.to_string()),
|
|
description: Set(Some(desc.to_string())),
|
|
created_at: Set(now),
|
|
updated_at: Set(now),
|
|
created_by: Set(system_user_id),
|
|
updated_by: Set(system_user_id),
|
|
deleted_at: Set(None),
|
|
version: Set(1),
|
|
};
|
|
perm.insert(db).await.map_err(|e| AuthError::Validation(e.to_string()))?;
|
|
}
|
|
|
|
// 2. Create "admin" role with all permissions
|
|
let admin_role_id = Uuid::now_v7();
|
|
let admin_role = role::ActiveModel {
|
|
id: Set(admin_role_id),
|
|
tenant_id: Set(tenant_id),
|
|
name: Set("管理员".to_string()),
|
|
code: Set("admin".to_string()),
|
|
description: Set(Some("系统管理员,拥有所有权限".to_string())),
|
|
is_system: Set(true),
|
|
created_at: Set(now),
|
|
updated_at: Set(now),
|
|
created_by: Set(system_user_id),
|
|
updated_by: Set(system_user_id),
|
|
deleted_at: Set(None),
|
|
version: Set(1),
|
|
};
|
|
admin_role.insert(db).await.map_err(|e| AuthError::Validation(e.to_string()))?;
|
|
|
|
// Assign all permissions to admin role
|
|
for perm_id in &perm_ids {
|
|
let rp = role_permission::ActiveModel {
|
|
role_id: Set(admin_role_id),
|
|
permission_id: Set(*perm_id),
|
|
tenant_id: Set(tenant_id),
|
|
created_at: Set(now),
|
|
updated_at: Set(now),
|
|
created_by: Set(system_user_id),
|
|
updated_by: Set(system_user_id),
|
|
deleted_at: Set(None),
|
|
version: Set(1),
|
|
};
|
|
rp.insert(db).await.map_err(|e| AuthError::Validation(e.to_string()))?;
|
|
}
|
|
|
|
// 3. Create "viewer" role with read-only permissions
|
|
let viewer_role_id = Uuid::now_v7();
|
|
let viewer_role = role::ActiveModel {
|
|
id: Set(viewer_role_id),
|
|
tenant_id: Set(tenant_id),
|
|
name: Set("查看者".to_string()),
|
|
code: Set("viewer".to_string()),
|
|
description: Set(Some("只读用户,可查看所有数据".to_string())),
|
|
is_system: Set(true),
|
|
created_at: Set(now),
|
|
updated_at: Set(now),
|
|
created_by: Set(system_user_id),
|
|
updated_by: Set(system_user_id),
|
|
deleted_at: Set(None),
|
|
version: Set(1),
|
|
};
|
|
viewer_role.insert(db).await.map_err(|e| AuthError::Validation(e.to_string()))?;
|
|
|
|
// Assign read permissions to viewer role
|
|
for idx in READ_PERM_INDICES {
|
|
if *idx < perm_ids.len() {
|
|
let rp = role_permission::ActiveModel {
|
|
role_id: Set(viewer_role_id),
|
|
permission_id: Set(perm_ids[*idx]),
|
|
tenant_id: Set(tenant_id),
|
|
created_at: Set(now),
|
|
updated_at: Set(now),
|
|
created_by: Set(system_user_id),
|
|
updated_by: Set(system_user_id),
|
|
deleted_at: Set(None),
|
|
version: Set(1),
|
|
};
|
|
rp.insert(db).await.map_err(|e| AuthError::Validation(e.to_string()))?;
|
|
}
|
|
}
|
|
|
|
// 4. Create super admin user
|
|
let admin_user_id = Uuid::now_v7();
|
|
let password_hash = password::hash_password(super_admin_password)?;
|
|
|
|
let admin_user = user::ActiveModel {
|
|
id: Set(admin_user_id),
|
|
tenant_id: Set(tenant_id),
|
|
username: Set("admin".to_string()),
|
|
email: Set(None),
|
|
phone: Set(None),
|
|
display_name: Set(Some("系统管理员".to_string())),
|
|
avatar_url: Set(None),
|
|
status: Set("active".to_string()),
|
|
last_login_at: Set(None),
|
|
created_at: Set(now),
|
|
updated_at: Set(now),
|
|
created_by: Set(system_user_id),
|
|
updated_by: Set(system_user_id),
|
|
deleted_at: Set(None),
|
|
version: Set(1),
|
|
};
|
|
admin_user.insert(db).await.map_err(|e| AuthError::Validation(e.to_string()))?;
|
|
|
|
// Create password credential for admin user
|
|
let cred = user_credential::ActiveModel {
|
|
id: Set(Uuid::now_v7()),
|
|
tenant_id: Set(tenant_id),
|
|
user_id: Set(admin_user_id),
|
|
credential_type: Set("password".to_string()),
|
|
credential_data: Set(Some(serde_json::json!({ "hash": password_hash }))),
|
|
verified: Set(true),
|
|
created_at: Set(now),
|
|
updated_at: Set(now),
|
|
created_by: Set(system_user_id),
|
|
updated_by: Set(system_user_id),
|
|
deleted_at: Set(None),
|
|
version: Set(1),
|
|
};
|
|
cred.insert(db).await.map_err(|e| AuthError::Validation(e.to_string()))?;
|
|
|
|
// 5. Assign admin role to admin user
|
|
let user_role_assignment = user_role::ActiveModel {
|
|
user_id: Set(admin_user_id),
|
|
role_id: Set(admin_role_id),
|
|
tenant_id: Set(tenant_id),
|
|
created_at: Set(now),
|
|
updated_at: Set(now),
|
|
created_by: Set(system_user_id),
|
|
updated_by: Set(system_user_id),
|
|
deleted_at: Set(None),
|
|
version: Set(1),
|
|
};
|
|
user_role_assignment.insert(db).await.map_err(|e| AuthError::Validation(e.to_string()))?;
|
|
|
|
tracing::info!(
|
|
tenant_id = %tenant_id,
|
|
admin_user_id = %admin_user_id,
|
|
"Seeded tenant auth: admin user, 2 roles, {} permissions",
|
|
DEFAULT_PERMISSIONS.len()
|
|
);
|
|
|
|
Ok(())
|
|
}
|