你已经分别掌握了 FastAPI 路由编写(第13篇)、PostgreSQL 数据操作(第14篇)和 JWT 认证(第15篇)。现在把这三块拼起来——构建一个真实的博客系统后端,包含用户注册、登录、发文章、编辑、删除的完整闭环。
这就好比盖房子:FastAPI 是钢筋骨架(路由与请求处理),PostgreSQL 是地基(数据持久存储),JWT 是门锁系统(身份验证)。三者缺一不可,组合起来才是一个能住人的房子。
| 层级 | 技术选型 | 版本 |
|---|---|---|
| Web 框架 | FastAPI | 0.139.x |
| 数据库 | PostgreSQL | 18 |
| ORM | SQLAlchemy 2.0 (async) | 2.0.x |
| 认证 | PyJWT + pwdlib[argon2] | 2.13.0 / 0.2.x |
| 数据验证 | Pydantic v2 | 2.x |
POST /register,密码 Argon2 哈希存储
POST /token,返回 JWT Token
POST /posts,需登录
GET /posts,公开访问,支持分页
PUT /posts/{id},仅作者可操作
DELETE /posts/{id},仅作者可操作
架构明确了,接下来搭骨架。一个清晰的项目结构能让代码各司其职,后期维护不混乱。我们把博客系统拆成五个模块:配置、数据库、模型、认证、路由。
一条命令装齐所有依赖:
各包的职责:
fastapi[standard] — 含 uvicorn 服务器和 Pydantic v2
sqlalchemy[asyncio] — SQLAlchemy 2.0 异步支持
asyncpg — PostgreSQL 异步驱动
pyjwt — JWT 签发与验证(2.13.0,2026-05 安全更新版)
pwdlib[argon2] — 密码哈希(替代已停止维护的 passlib)
把敏感信息放进 .env 文件,不硬编码在源码里:
然后在 config.py 中读取:
配置就绪后,先定义数据结构。博客系统只需两张表:users(用户表)和 posts(文章表),通过外键关联——一篇文章必定属于一个用户。
database.py 负责创建异步引擎和 Session 工厂:
expire_on_commit=False 很关键:默认 commit 后 Session 中的对象会过期,异步环境下重新查询会报错。设为 False 让对象在 commit 后仍然可用。两张表通过 user_id 外键关联,并设置 CASCADE 删除规则——用户被删时,其文章一并删除:
Pydantic 模型负责接口数据的验证和序列化——进来的数据要校验,出去的数据要过滤。绝不能把 hashed_password 返回给客户端:
model_config = ConfigDict(from_attributes=True) 让 Pydantic 自动从 SQLAlchemy 对象读取属性。数据库表建好了,接下来实现安全认证。这里复用第15篇的知识:pwdlib + Argon2 做密码哈希,PyJWT 签发 Token。把认证逻辑独立到 auth.py 中,保持代码整洁。
注册流程:接收用户名/邮箱/密码 → 检查是否已存在 → 密码哈希 → 存入数据库 → 返回用户信息(不含密码)。
登录流程:接收 OAuth2 表单格式的用户名/密码 → 查库验证 → 签发 JWT Token。使用 OAuth2PasswordRequestForm 保证 Swagger UI 的"Authorize"按钮可用。
sub 是 JWT 标准声明字段(RFC 7519),表示 Token 的主体,这里存用户名。把"从 Token 提取当前用户"封装为公共依赖,所有需要登录的接口只需声明 Depends(get_current_user) 即可:
认证模块就绪,现在实现博客核心功能——文章的增删改查。关键设计:创建/编辑/删除需要登录,且编辑和删除只能操作自己的文章;列表和详情公开访问。
编辑和删除接口需要双重校验:先验证登录状态,再验证当前用户是否是文章作者。这通过 post.user_id != current_user.id 判断实现:
| 接口 | 方法 | 认证 | 额外限制 |
|---|---|---|---|
| /register | POST | 公开 | 用户名唯一 |
| /token | POST | 公开 | 返回 JWT |
| /posts | GET | 公开 | 支持分页 |
| /posts/{id} | GET | 公开 | — |
| /posts | POST | 需登录 | — |
| /posts/{id} | PUT | 需登录 | 仅作者 |
| /posts/{id} | DELETE | 需登录 | 仅作者 |
所有接口代码写完了,现在启动服务、建库建表、用 curl 走一遍完整流程:注册 → 登录拿 Token → 发文章 → 查列表 → 编辑 → 删除。
先在 PostgreSQL 中创建数据库和用户,然后启动 FastAPI:
用 curl 逐步测试每个接口:
除了 curl,FastAPI 自带的 Swagger UI 是更直观的测试工具。打开浏览器访问 http://localhost:8000/docs,点击右上角"Authorize"按钮,输入用户名密码登录后,所有需要认证的接口都可以直接在页面上测试。
openssl rand -hex 32 生成强密钥替换 .env 中的 SECRET_KEY;2)用 Alembic 管理数据库迁移而非 create_all 自动建表;3)添加 CORS 中间件允许前端跨域访问:app.add_middleware(CORSMiddleware, ...)。恭喜!你刚刚从零搭建了一个完整的博客后端系统。这不是玩具代码——它使用了异步数据库引擎、Argon2 密码哈希、JWT 无状态认证、Pydantic v2 数据验证,每一项都是生产级技术选型。
从第09篇到第16篇,你走完了 Web 全栈的核心路径:
| 篇目 | 核心技能 |
|---|---|
| 09 HTML | 语义化标签、表单、表格 |
| 10 CSS | 选择器、盒模型、Flex 布局、响应式 |
| 11 JavaScript | 变量、DOM 操作、事件处理 |
| 12 HTTP | 请求/响应结构、状态码、RESTful |
| 13 FastAPI | 路由、Pydantic 验证、Swagger UI |
| 14 PostgreSQL | SQL 操作、表设计、SQLAlchemy 集成 |
| 15 认证授权 | JWT、Session、Cookie、Argon2 哈希 |
| 16 综合实战 | 整合三者构建完整博客系统 |
GET /users/me 接口,返回当前登录用户的信息。提示:复用 get_current_user 依赖,response_model 用 UserOut。GET /posts?search=关键词,按标题模糊匹配。提示:SQLAlchemy 中用 Post.title.contains(search) 或 ilike() 方法。POST /posts/{id}/comments(需登录)和 GET /posts/{id}/comments(公开)两个接口。需要新建 Comment 模型、CommentCreate/CommentOut schema,并配置 Post-Comment 一对多关系。HTML / CSS / JavaScript / HTTP / FastAPI / PostgreSQL / JWT / 综合实战 — 8 篇全部完成