📖 文章摘要
22 个 API 端点分公开/网盘/管理三层。本文详解文章列表分页、全文搜索、JWT 认证和安全机制的设计与实现。
API 设计:22 个端点三层架构
博客后端共 22 个 API 端点,分为公开接口、网盘接口、管理接口三个层级。
层级 1:公开接口(9 个)
无需认证,任何人都可访问:
| 方法 | 路径 | 说明 |
|---|---|---|
| GET | /api/articles |
文章列表(分页 + 分类/标签筛选) |
| GET | /api/articles/{slug} |
文章详情(自动 +1 阅读量) |
| GET | /api/categories |
分类列表 |
| GET | /api/tags |
标签列表 |
| GET | /api/search?q= |
全文搜索(标题 + 正文 + 摘要) |
| POST | /api/comments |
提交评论 |
| GET | /api/comments/{id} |
评论列表 |
| GET | /api/feed/rss |
RSS 订阅 |
| GET | /api/site |
站点信息 |
文章列表 API 实现
@router.get("", response_model=dict)
def list_articles(
page: int = Query(1, ge=1),
size: int = Query(24, ge=1, le=50),
category: str = None,
tag: str = None,
db: Session = Depends(get_db),
):
query = db.query(Article).filter(Article.is_published == True)
if category:
query = query.join(Article.category).filter(Category.slug == category)
query = query.order_by(desc(Article.is_top), desc(Article.published_at))
total = query.count()
items = query.offset((page - 1) * size).limit(size).all()
return {
"items": [ArticleListItem.model_validate(a) for a in items],
"total": total, "page": page, "size": size,
"pages": (total + size - 1) // size,
}
关键点:
- 使用
ArticleListItem.model_validate(a)通过 Pydantic schema 序列化,确保响应格式一致 model_validate在 Pydantic v2 中是严格模式——字段类型不匹配会直接报错is_top降序排列保证置顶文章始终在前面
全文搜索实现
query = db.query(Article).filter(
Article.is_published == True,
or_(
Article.title.ilike(f"%{q}%"),
Article.content_md.ilike(f"%{q}%"),
Article.summary.ilike(f"%{q}%"),
),
)
SQLite 的 ILIKE 支持大小写不敏感匹配,虽然在大数据量下性能不佳,但对几百篇文章的博客完全够用。
层级 2:网盘接口(6 个)
网盘功能需要双重验证(见第 8 篇文章详解):
| 方法 | 路径 | 认证 |
|---|---|---|
| POST | /api/pan/upload |
管理员密码 |
| POST | /api/pan/{id}/verify |
文件密码 |
| GET | /api/pan/{id}/download |
Token(5 分钟有效) |
| GET | /api/pan |
JWT |
| GET | /api/pan/{id}/logs |
JWT |
| DELETE | /api/pan/{id} |
JWT |
层级 3:管理接口(7 个)
所有管理接口通过 JWT 认证:
| 方法 | 路径 | 说明 |
|---|---|---|
| POST | /api/auth/login |
登录 |
| GET/POST/PUT/DELETE | /api/admin/articles |
文章 CRUD |
| PATCH | /api/admin/articles/{id}/publish |
发布/下架 |
| GET/POST/DELETE | /api/admin/categories |
分类管理 |
| GET/POST/DELETE | /api/admin/tags |
标签管理 |
| GET/POST | /api/admin/comments |
评论审核 |
| POST | /api/admin/upload |
图片上传 |
| PUT | /api/admin/site |
站点配置 |
JWT 认证实现
def create_token(admin_id: int) -> str:
expire = datetime.now(timezone.utc) + timedelta(days=7)
payload = {"sub": str(admin_id), "exp": expire}
return jwt.encode(payload, SECRET_KEY, algorithm="HS256")
def get_current_admin(credentials, db) -> Admin:
payload = jwt.decode(credentials, SECRET_KEY, algorithms=["HS256"])
admin_id = int(payload.get("sub"))
admin = db.query(Admin).filter(Admin.id == admin_id).first()
if not admin:
raise HTTPException(401)
return admin
认证流程:
- 前端登录 → 后端签发 JWT(存 cookie)
- 每次 API 请求携带 JWT
- 管理接口通过
Depends(get_current_admin)自动拦截未认证请求 - 前端 Axios 响应拦截器检测 401 → 清除 cookie → 跳转登录页
安全设计总结
- JWT 7 天有效期,无 refresh token 机制(单用户博客简化处理)
- 密码 SHA256 存储(非加盐,权衡安全性 vs 兼容性)
- 评论默认隐藏,需要管理员审核通过才显示
- 网盘双重验证:密码 → 5 分钟有效 token → 文件
- 后端服务绑定 127.0.0.1,不对外暴露端口
最后更新:2026年6月29日CC BY-NC-SA 4.0
评论
暂无评论,来写第一条吧
