"""RBAC 种子:权限、角色与默认账号。""" from __future__ import annotations from sqlalchemy.orm import Session from models import Permission, Role, RolePermission, User, UserRole from services.security import hash_password PERMISSIONS = [ ("learning:use", "使用学习功能", "learning"), ("users:manage", "用户管理", "admin"), ("catalog:manage", "教材/课程管理", "admin"), ("question-bank:manage", "题库管理", "admin"), ("llm:manage", "模型配置管理", "admin"), ("knowledge:manage", "知识图谱管理", "admin"), ] ROLES = { "admin": { "name": "管理员", "description": "拥有用户、模型、教材课程与题库的全部管理权限", # 管理员是纯管理账号,不参与学习,因此不授予 learning:use "permissions": [ code for code, _, _ in PERMISSIONS if code != "learning:use" ], }, "student": { "name": "普通用户", "description": "使用学习总览、练习、错题、分析等学习功能", "permissions": ["learning:use"], }, } DEFAULT_USERS = [ ("admin", "admin123", "系统管理员", "admin"), ("student", "student123", "演示学生", "student"), ] def _permission_map(db: Session) -> dict[str, Permission]: rows = {row.code: row for row in db.query(Permission).all()} for code, name, group in PERMISSIONS: if code not in rows: row = Permission(code=code, name=name, group=group) db.add(row) db.flush() rows[code] = row return rows def ensure_rbac(db: Session) -> None: """幂等创建权限、角色与默认账号,并同步旧库中已过期的角色权限。""" permissions = _permission_map(db) roles = {row.code: row for row in db.query(Role).all()} for code, meta in ROLES.items(): if code not in roles: role = Role(code=code, name=meta["name"], description=meta["description"]) db.add(role) db.flush() roles[code] = role expected = set(meta["permissions"]) existing_rows = ( db.query(RolePermission, Permission.code) .join(Permission, Permission.id == RolePermission.permission_id) .filter(RolePermission.role_id == roles[code].id) .all() ) for role_permission, permission_code in existing_rows: if permission_code not in expected: db.delete(role_permission) for permission_code in meta["permissions"]: exists = ( db.query(RolePermission) .filter( RolePermission.role_id == roles[code].id, RolePermission.permission_id == permissions[permission_code].id, ) .first() ) if exists is None: db.add( RolePermission( role_id=roles[code].id, permission_id=permissions[permission_code].id, ) ) db.flush() for username, password, display_name, role_code in DEFAULT_USERS: user = db.query(User).filter(User.username == username).first() if user is None: user = User( username=username, password_hash=hash_password(password), display_name=display_name, active=True, ) db.add(user) db.flush() assignment = ( db.query(UserRole) .filter( UserRole.user_id == user.id, UserRole.role_id == roles[role_code].id, ) .first() ) if assignment is None: db.add(UserRole(user_id=user.id, role_id=roles[role_code].id)) db.commit()