后端 FastAPI 六层结构(api/services/repositories/models/schemas/core), 统一响应信封、全局异常、日志脱敏;6 张表经 Alembic 迁移建库,SQL 留存 db/migration;登录鉴权含图形验证码(Redis GETDEL 防重放)、JWT、登录限流、 登出黑名单(TTL=令牌剩余有效期)、登录日志。 前端 Vue3 + TS + Element Plus 骨架,含登录页、路由守卫、请求封装与 Vite 代理。 工程配置:uv 锁定 Python 3.12、ruff 检查与格式化、editorconfig、gitattributes。 测试 184 项(单元 155 / 集成 29)全绿,浏览器端到端 8 项通过。 Co-Authored-By: Claude Code <noreply@anthropic.com>
106 lines
3.9 KiB
Python
106 lines
3.9 KiB
Python
"""角色、权限及其关联模型(RBAC 标准五表的后四张)。
|
||
|
||
权限与角色是多对多:一个权限(如「计提参数配置」)可授予多个角色,
|
||
因此关联必须独立成表,不能把 role_id 塞进 permissions 表。
|
||
"""
|
||
|
||
from datetime import datetime
|
||
from typing import TYPE_CHECKING
|
||
|
||
from sqlalchemy import DateTime, ForeignKey, Index, Integer, String, UniqueConstraint, text
|
||
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
||
|
||
from app.models.base import BIGINT_UNSIGNED, TINYINT_TYPE, Base, TimestampMixin, mysql_table_args
|
||
|
||
if TYPE_CHECKING:
|
||
from app.models.user import UserRole
|
||
|
||
|
||
class Role(Base, TimestampMixin):
|
||
"""角色表。本期仅 admin / user 两个角色,数据随迁移脚本初始化。"""
|
||
|
||
__tablename__ = "roles"
|
||
__table_args__ = mysql_table_args("角色表")
|
||
|
||
id: Mapped[int] = mapped_column(
|
||
BIGINT_UNSIGNED, primary_key=True, autoincrement=True, comment="主键ID"
|
||
)
|
||
role_code: Mapped[str] = mapped_column(
|
||
String(32), nullable=False, unique=True, comment="角色编码:admin系统管理员 user普通用户"
|
||
)
|
||
role_name: Mapped[str] = mapped_column(String(64), nullable=False, comment="角色名称")
|
||
description: Mapped[str | None] = mapped_column(String(255), comment="角色说明")
|
||
sort_order: Mapped[int] = mapped_column(
|
||
Integer, nullable=False, server_default="0", comment="显示排序"
|
||
)
|
||
status: Mapped[int] = mapped_column(
|
||
TINYINT_TYPE, nullable=False, server_default="1", comment="状态:1启用 0禁用"
|
||
)
|
||
|
||
user_roles: Mapped[list["UserRole"]] = relationship(back_populates="role")
|
||
|
||
|
||
class Permission(Base, TimestampMixin):
|
||
"""权限表。
|
||
|
||
perm_type 区分菜单/按钮/接口三类,parent_id 支撑树形结构。
|
||
本期只建表不填数据 —— 具体权限清单待需求澄清后确定。
|
||
"""
|
||
|
||
__tablename__ = "permissions"
|
||
__table_args__ = mysql_table_args("权限表")
|
||
|
||
id: Mapped[int] = mapped_column(
|
||
BIGINT_UNSIGNED, primary_key=True, autoincrement=True, comment="主键ID"
|
||
)
|
||
perm_code: Mapped[str] = mapped_column(
|
||
String(128), nullable=False, unique=True, comment="权限编码,如 system:user:create"
|
||
)
|
||
perm_name: Mapped[str] = mapped_column(String(64), nullable=False, comment="权限名称")
|
||
perm_type: Mapped[int] = mapped_column(
|
||
TINYINT_TYPE, nullable=False, server_default="1", comment="类型:1菜单 2按钮 3接口"
|
||
)
|
||
parent_id: Mapped[int | None] = mapped_column(
|
||
BIGINT_UNSIGNED,
|
||
ForeignKey("permissions.id", ondelete="CASCADE"),
|
||
comment="父权限ID(permissions.id),顶级为空",
|
||
)
|
||
sort_order: Mapped[int] = mapped_column(
|
||
Integer, nullable=False, server_default="0", comment="显示排序"
|
||
)
|
||
status: Mapped[int] = mapped_column(
|
||
TINYINT_TYPE, nullable=False, server_default="1", comment="状态:1启用 0禁用"
|
||
)
|
||
|
||
|
||
class RolePermission(Base):
|
||
"""角色-权限关联表。"""
|
||
|
||
__tablename__ = "role_permissions"
|
||
__table_args__ = mysql_table_args(
|
||
"角色权限关联表",
|
||
UniqueConstraint(
|
||
"role_id", "permission_id", name="uk_role_permissions_role_id_permission_id"
|
||
),
|
||
Index("idx_role_permissions_permission_id", "permission_id"),
|
||
)
|
||
|
||
id: Mapped[int] = mapped_column(
|
||
BIGINT_UNSIGNED, primary_key=True, autoincrement=True, comment="主键ID"
|
||
)
|
||
role_id: Mapped[int] = mapped_column(
|
||
BIGINT_UNSIGNED,
|
||
ForeignKey("roles.id", ondelete="CASCADE"),
|
||
nullable=False,
|
||
comment="角色ID(roles.id)",
|
||
)
|
||
permission_id: Mapped[int] = mapped_column(
|
||
BIGINT_UNSIGNED,
|
||
ForeignKey("permissions.id", ondelete="CASCADE"),
|
||
nullable=False,
|
||
comment="权限ID(permissions.id)",
|
||
)
|
||
create_time: Mapped[datetime] = mapped_column(
|
||
DateTime, nullable=False, server_default=text("CURRENT_TIMESTAMP"), comment="创建时间"
|
||
)
|