Level 32 / 阅读练习

从 0 到 1 做一个用户管理系统

把前端页面、FastAPI 接口、数据库、登录鉴权和权限控制串成一个完整小后台。

Progress

阅读中

0/2 步完成 / 阅读后完成练习才算通关

Practice

本关怎么过

  • 读完正文后确认完成阅读
  • 完成 1 道选择题练习
  • 答错时看解释,再回到正文补理解

一句话:用户管理系统就是把前端页面、后端接口、数据库、登录鉴权和权限控制串成一个真正能用的小后台。

本篇学完你会什么:知道一个用户管理系统应该先做什么、后做什么,前端和后端怎么分工,哪些功能先做最小版,哪些功能等主线跑通后再补。

1. 为什么用用户管理系统做综合实战

前面很多文章分别讲了:

  • React / Vue 页面怎么写
  • FastAPI 接口怎么写
  • SQL 和 CRUD 怎么做
  • JWT 登录鉴权怎么做
  • Redis、Docker、测试和工程化怎么补

但真实开发不是一篇文章一个孤岛。真实项目里,你会遇到的是一整条链路:

用户点新增按钮
  ↓
前端打开表单
  ↓
提交 POST /api/v1/users
  ↓
后端校验参数和权限
  ↓
写入数据库
  ↓
返回结果
  ↓
前端刷新列表

用户管理系统刚好能把这些能力串起来,而且规模不大,适合做第一个综合项目。

2. 最小可用版本包含什么

不要一开始就做得很大。第一版只做这些:

模块必做功能暂时不做
登录用户名密码登录、保存 tokenrefresh token、扫码登录
用户列表分页、搜索、状态筛选高级筛选、导出 Excel
新增用户用户名、邮箱、角色、状态头像、复杂组织结构
编辑用户修改邮箱、角色、状态修改密码策略
删除用户删除确认、后端权限校验批量删除、回收站
权限管理员才能新增/删除复杂数据权限

大白话:第一版不是“把后台系统一次写完”,而是先写出一条能闭环的主路。

3. 前后端怎么分工

可以按这张表分:

事情前端负责后端负责
页面展示表格、表单、弹窗、按钮状态返回前端需要的数据
表单校验必填提示、格式提示最终校验,不能信任前端
登录状态保存 token、请求时带 token签发 token、校验 token
权限展示没权限就隐藏按钮或禁用按钮没权限直接返回 403
分页搜索收集搜索条件、展示页码根据条件查询数据库
错误处理展示错误信息返回清楚的错误码和错误消息

重点:前端权限只是体验,后端权限才是安全底线。

4. 数据库先设计哪些表

最小版可以先有 3 张表:

users 用户表
roles 角色表
user_roles 用户和角色关系表

如果你想更完整一点,再加:

permissions 权限表
role_permissions 角色和权限关系表

这里容易混淆:最小 3 张表并不是没有权限,而是先把权限从角色名里推出来。

比如先约定:

admin 角色 -> user:read、user:create、user:update、user:delete
operator 角色 -> user:read、user:update

这样登录接口仍然可以返回 permissions,只是这些权限暂时由代码根据角色生成。

等你需要在页面上管理权限、经常新增按钮权限,或者不同角色的权限变化很频繁,再把 permissionsrole_permissions 做成数据库表。这样从最小版走到完整版会更顺。

最小用户表字段:

字段作用
id用户唯一 id
username登录名,不能重复
email邮箱
password_hash密码 hash,不存明文密码
is_active是否启用
created_at创建时间
updated_at更新时间

先不要急着设计几十个字段。字段越多,表单、校验、接口和测试都会一起变复杂。

5. 后端接口怎么排顺序

建议按这个顺序写:

顺序接口为什么先做
1POST /auth/login没登录就没有后续权限
2GET /auth/me前端刷新后要知道当前用户是谁
3GET /users先把列表展示出来
4POST /users再做新增
5PUT /users/{id}再做编辑
6DELETE /users/{id}最后做删除和危险操作

每个接口都按同一个套路:

路由接请求
  ↓
Pydantic 校验参数
  ↓
Depends 校验当前用户和权限
  ↓
Service 处理业务
  ↓
Repository 查写数据库
  ↓
Response Schema 返回给前端

6. 前端页面怎么排顺序

前端也不要一口气全写。建议:

  1. 先写登录页,能拿到 token。
  2. 再写用户列表页,能请求并展示数据。
  3. 再加搜索和分页。
  4. 再加新增弹窗。
  5. 再复用弹窗做编辑。
  6. 最后加删除确认和权限按钮。

页面状态至少要有:

状态例子
loading列表加载中
error接口报错
empty没有数据
submitting表单保存中
forbidden没权限

这几个状态比页面好不好看更重要。真实用户最怕的是点了没反应、错了不知道为什么。

7. 登录和权限怎么接进去

登录以后,前端通常拿到:

{
  "access_token": "eyJxxx",
  "user": {
    "id": 1,
    "username": "admin"
  },
  "permissions": ["user:read", "user:create", "user:update", "user:delete"]
}

前端做三件事:

  1. 保存 token。
  2. 请求时带上 Authorization: Bearer <token>
  3. 根据 permissions 控制按钮显示。

如果你还在最小 3 表版本,permissions 可以由后端根据角色名生成;如果已经有权限表,就从 role_permissions 查询出来。前端不关心权限从哪里来,只关心最后拿到的权限码列表是否稳定。

后端也做三件事:

  1. 解析 token,确认用户是谁。
  2. 查询用户是否启用。
  3. 判断当前接口需要的权限是否满足。

不要只做前端按钮隐藏。用户可以绕过页面直接请求接口,所以后端必须拦住。

8. 一条新增用户流程怎么跑通

以新增用户为例:

点击新增
  ↓
打开 UserForm
  ↓
填写 username / email / password / role
  ↓
前端校验必填
  ↓
POST /api/v1/users
  ↓
后端检查 user:create 权限
  ↓
后端检查 username 是否重复
  ↓
密码 hash 后写入 users 表
  ↓
返回新用户
  ↓
前端关闭弹窗并刷新列表

这条链路能跑通,说明你的项目已经不是单点练习,而是前后端真的连起来了。

9. 项目目录建议

后端:

app/
├── api/v1/auth.py
├── api/v1/users.py
├── core/security.py
├── models/user.py
├── models/role.py
├── schemas/auth.py
├── schemas/user.py
├── services/user_service.py
└── repositories/user_repository.py

前端:

src/
├── api/users.ts
├── api/auth.ts
├── stores/auth.ts
├── pages/login/
├── pages/users/
├── components/UserForm.vue
└── components/UserTable.vue

大白话:后端按接口、数据、业务分层;前端按页面、接口、状态、组件分工。

10. 常见错误

错误后果修正
先写 UI,不写接口契约前后端联调时反复改字段先定接口字段和错误码
前端校验通过就信任数据被绕过后写入脏数据后端必须再校验
只隐藏按钮,不校验后端权限直接请求接口能越权后端接口加权限依赖
列表没有分页数据多了页面很慢一开始就设计 page/page_size
删除直接执行误删风险高前端确认,后端权限校验
密码明文保存严重安全问题只保存 password_hash

11. 实战检查清单

[ ] 登录接口能返回 token
[ ] 前端请求能自动带 Authorization
[ ] 刷新页面后能恢复当前用户
[ ] 用户列表支持分页和搜索
[ ] 新增用户会校验用户名重复
[ ] 编辑用户不会误改密码字段
[ ] 删除用户需要管理员权限
[ ] 没权限时后端返回 403
[ ] 前端能展示 loading、error、empty 状态
[ ] 数据库字段变化有迁移记录

12. 总结表

名词大白话
用户管理系统把用户、角色、权限、登录串起来的小后台
最小可用版先做能登录、能看列表、能增删改
接口契约前后端约好的请求字段和返回字段
权限码判断能不能做某件事的标记
Service放业务规则
Repository放数据库读写
前端状态loading、error、empty、submitting 这些页面反馈

下一篇建议:大白话讲解——前后端接口联调.md

Checkpoint

读完后做题闯关

先读正文,再用下面的选择题检查自己是否真的理解。答错会出现解释,可以回到正文补一眼再重选。

0/1
先完成阅读

读完正文后点击“我已读完,进入练习”,题目会变成可答状态。

第 1 题

读完这一篇后,最适合怎么确认自己真的理解了?