Files
guzhujushiBlog/README.md
T

8.1 KiB
Raw Blame History

孤竹居士的个人博客

部署在阿里云 Ubuntu 上的个人全栈博客系统:原生前端 SPA + FastAPI + SQLite。

技术架构

技术
服务器 Ubuntu Linux + Nginx
前端 原生 HTML + CSS + JavaScriptSPAHistory API 路由)
后端 Python FastAPI(仅监听 127.0.0.1:8080
数据库 SQLite + SQLAlchemy ORM
认证 JWT Tokenbcrypt 存储密码哈希)
文件 Nginx 静态访问 uploads 目录
  • Nginx80HTTP/ 443HTTPS,待配置);/api/* 反代到 127.0.0.1:8080/uploads/* 静态映射。
  • 端口:22 SSH、80 HTTP、443 HTTPS、25565 Minecraft(独立运行,不占用博客端口)。

目录结构

blog/
├── frontend/            # 前端源码(原生 SPAES Modules 拆分)
│   ├── index.html
│   ├── style.css
│   ├── main.js          # 入口:初始化 + 全局事件
│   ├── api.js           # 网络层:api() / uploadFile()
│   ├── auth.js          # 登录 / 注册 / 会话
│   ├── router.js        # 路由与页面壳(导航栏、用户区)
│   ├── article.js       # 文章列表 / 详情 / 分区 / 简介视图
│   ├── comment.js       # 评论与回复
│   ├── friend.js        # 好友申请
│   ├── manage.js        # 博主管理面板(发文 / 编辑 / 简介设置)
│   ├── markdown.js      # Markdown 轻量渲染(含 URL 白名单)
│   ├── state.js         # 全局常量与状态
│   └── utils.js         # DOM / 日期 / 弹窗 / Toast 工具
├── backend/
│   ├── main.py          # FastAPI 实例 + 路由注册 + 统一错误格式
│   ├── database.py      # SQLite 连接与初始化
│   ├── models.py        # ORM 模型(User/Article/Comment/Like/Friend/EmailCode
│   ├── schemas.py       # Pydantic 请求/响应模型
│   ├── auth.py          # bcrypt + JWT + 当前用户依赖
│   ├── security.py      # 邮箱校验、IP 提取、内存限流器
│   ├── email.py         # SMTP 验证码发送
│   ├── seed.py          # 博主账号初始化(python -m backend.seed
│   └── routers/         # 业务路由(user/article/comment/like/friend/email/password/upload
├── uploads/
│   ├── avatar/          # 头像
│   ├── article/         # 文章图片(封面/插图)
│   └── project/         # 项目文件(zip
├── .env                 # 环境配置(已被 .gitignore 忽略,勿提交)
├── .env.example         # 环境变量模板(全中文注释)
├── requirements.txt     # Python 依赖
└── README.md

快速开始(本地开发)

  1. 安装依赖:pip install -r requirements.txt
  2. 配置环境:复制 .env.example.env,填写 JWT_SECRETBLOGGER_*SMTP_*
  3. 初始化数据库与博主:python -m backend.seed
  4. 启动后端:uvicorn backend.main:app --host 127.0.0.1 --port 8080
  5. 启动前端:任意静态服务器指向 frontend/,并将 /api/* 反代到 127.0.0.1:8080/uploads/* 映射到 uploads/(本地开发可借助 Nginx 或简单代理脚本实现)。

提示:前端为 SPA,任意路径(如 /article/1)都应回退到 index.html

权限与角色

角色 权限
visitor(游客) 查看公开文章、申请好友(好友文章仅显示标题与封面)
friend(好友) 查看公开与好友文章、评论(含回复)、点赞
blogger(博主) 全部权限:发布/编辑/删除文章、审批好友申请、上传图片与项目、修改简介与头像

API 一览(统一前缀 /api,统一响应 {success, data, message}

认证与资料

  • POST /api/register 注册(邮箱/用户名/密码,bcrypt 存储)
  • POST /api/login 登录(JWT;失败限流)
  • GET /api/user/level 当前角色
  • GET /api/user/me 当前用户资料
  • GET /api/user/blogger 博主公开资料(简介页)
  • PUT /api/user/profile 更新头像/简介

文章

  • POST /api/article/add 发布(仅博主)
  • GET /api/article/list?page=&page_size= 列表(分页;好友文章对游客仅标题+封面)
  • GET /api/article/{id} 详情(好友文章对游客锁定正文)
  • PUT /api/article/{id} 编辑(仅博主)
  • DELETE /api/article/{id} 删除(仅博主,级联评论/点赞)

评论 / 点赞 / 好友

  • POST /api/comment/add 评论或回复(parent_id 可选;仅好友/博主)
  • GET /api/comment/list?article_id= 评论列表
  • POST /api/like/add 点赞(好友/博主,不可重复)
  • GET /api/like/list?article_id= 点赞列表
  • POST /api/friend/apply 申请好友 / GET /api/friend/status 好友状态
  • GET /api/friend/applications 申请列表(仅博主)
  • POST /api/friend/{id}/approve|reject 审批(仅博主)

邮箱验证码 / 密码

  • POST /api/email/send-code 发送验证码(邮箱+IP 限流)
  • POST /api/email/verify-code 校验验证码(尝试次数限制)
  • POST /api/password/forgot 忘记密码 / POST /api/password/reset 重置密码

上传

  • POST /api/upload/avatar 头像(jpg/png/webp,≤2MB
  • POST /api/upload/article 文章图片(仅博主,≤5MB
  • POST /api/upload/project 项目文件(仅博主,zip,≤50MB)

安全说明

  • 密码 bcrypt 哈希存储,禁止明文;localStorage 仅保存 token 与用户名。
  • JWT_SECRET 缺失时后端拒绝启动(fail-fast),禁止硬编码弱密钥。
  • 登录、验证码发送/校验均有内存限流(阈值可在 .env 调整)。
  • 上传文件:白名单扩展名 + 魔数校验 + 随机文件名,禁止执行用户上传内容。
  • 前端 Markdown 渲染带 URL 协议白名单(javascript:/data: 等被拦截)+ CSP 响应头/标签(纵深防御)。
  • 后端仅监听 127.0.0.1:8080,禁止公网直连。
  • 注册接口对“邮箱 / 用户名已占用”返回统一提示,且先核验验证码再查唯一性(防枚举);注册失败会作废本次验证码,需重新发送后再试。

部署(阿里云)

详细的 Nginx 站点配置与 systemd 服务文件将在后续任务中补充(当前仅给出要点)。

  1. 上传项目到 /var/www/blog,安装依赖:pip install -r requirements.txt
  2. 配置 .env(强随机 JWT_SECRET、博主账号、SMTP、安全限流)。
  3. python -m backend.seed 初始化数据库与博主。
  4. Nginx80 端口托管 frontend/ 静态文件;/api/* 反代 127.0.0.1:8080/uploads/* 映射 uploads/SPA 回退 index.html
  5. systemd 守护 uvicorn(开机自启、崩溃重启)。
  6. 安全组仅开放 22 / 80 / 443 / 25565。

数据库升级说明(仅旧库需要)

全新部署无需迁移:python -m backend.seed 会自动按最新结构建表。

若从旧版本升级(服务器上已有 backend/blog.db),需先补齐新字段再重启服务:

# 服务器(Ubuntu)执行;正式升级前建议先备份 backend/blog.db 与 uploads/
cd /var/www/blog
python3 - <<'EOF'
import sqlite3, datetime
con = sqlite3.connect("backend/blog.db")
con.execute("ALTER TABLE users ADD COLUMN token_version INTEGER NOT NULL DEFAULT 0")
con.execute("ALTER TABLE friends ADD COLUMN created_time DATETIME")
con.execute("ALTER TABLE articles ADD COLUMN category VARCHAR(30) NOT NULL DEFAULT 'life'")
con.execute("ALTER TABLE users ADD COLUMN avatar_updated_time DATETIME")
now = datetime.datetime.now(datetime.UTC).replace(tzinfo=None)  # 与后端 utcnow() 一致:无时区 UTC
con.execute("UPDATE friends SET created_time=? WHERE created_time IS NULL", (now,))
con.commit()
con.close()
print("数据库升级完成")
EOF

本地开发(Windows)若仅为调试数据,可省略迁移:删除 backend/blog.db 后重新执行 python -m backend.seed 即可。

字段说明:

  • users.token_version:JWT 令牌版本号。重置密码后版本自增,该用户所有旧令牌立即失效(登录状态吊销)。
  • friends.created_time:好友申请创建时间,用于博主审批列表展示申请时间。