Files
go_blog/README.md
T
kevin c9f858b626 fix: 完成 P2 安全修复 #9-13 #22-25
- #9 CDN 本地化:marked/DOMPurify/highlight.js/cropperjs/easymde 入 static/vendor(go:embed),Tailwind 改静态构建(scripts/build_tailwind.sh),CSP 收紧为 default-src 'self'
- #10 登录限速:IP+用户名维度 5 次失败锁 15 分钟,内存实现有界(handlers/login_ratelimit.go)
- #25 计时侧信道:用户不存在时执行 dummy bcrypt 抹平时间差(随 #10 实施)
- #11 配置文件权限 0640
- #12 首启随机一次性密码(弃用 admin/admin)
- #13 unix socket 660 + 代理用户加组提示
- #22 storage_dir 路径穿越校验(单安全路径段)
- #23 密码最小长度统一(改密/建号/重置),#24 邮箱格式统一校验
- 新增 13 个单元测试;go test ./... 含 -race 全绿
2026-08-27 18:10:22 +08:00

237 lines
10 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Go Blog
一个简洁、快速的博客引擎,使用 Go + Gin + Tailwind CSS 构建。支持 SQLite 和 MySQL,首次运行自动完成配置。
## 功能特性
- **文章管理** — 文章的创建、编辑、删除,支持标签分类、自定义发布时间和更新时间
- **Markdown 渲染** — 文章与评论支持 GFM Markdown(表格、任务列表、删除线),代码块语法高亮 + 一键复制,标题锚点链接,图片懒加载与灯箱预览
- **评论系统** — 文章评论功能,后台可审核(通过/拒绝/删除),支持评论设置
- **用户系统** — 用户注册、登录,角色分为管理员(admin)和作者(author
- **角色权限** — 管理员可访问后台管理面板;作者可管理自己的文章
- **个人中心** — 上传头像(支持裁剪)、编辑个人信息、修改密码
- **站点设置** — 自定义站点标题、副标题、favicon 图标
- **导航管理** — 自定义首页导航链接,支持图标
- **瀑布流布局** — 首页文章以瀑布流展示,支持无限滚动加载
- **阅读统计** — 文章阅读量统计,带机器人流量检测
- **附件上传** — 文章支持上传附件,基于内容寻址自动去重
- **RSS 订阅** — 自动生成 RSS Feed`/rss``/feed`
- **搜索功能** — 文章全文搜索
- **多语言** — 支持中文 / English,自动检测浏览器语言或手动切换
- **自适应界面** — Tailwind CSS,桌面端和移动端均可正常使用
- **开箱即用** — 首次运行自动创建配置文件、数据库和管理员账号
## 技术栈
| 层级 | 库/工具 |
|---|---|
| 路由 | [gin](https://github.com/gin-gonic/gin) |
| ORM | [gorm](https://gorm.io) |
| SQLite | [glebarez/sqlite](https://github.com/glebarez/sqlite)(纯 Go,无需 CGO |
| Session | [gin-contrib/sessions](https://github.com/gin-contrib/sessions) |
| 配置 | [gopkg.in/yaml.v3](https://gopkg.in/yaml.v3) |
| 密码 | [golang.org/x/crypto](https://pkg.go.dev/golang.org/x/crypto/bcrypt) |
| CSS | [Tailwind CSS](https://tailwindcss.com)(构建期静态生成,见 `scripts/build_tailwind.sh` |
## 快速开始
```bash
go run .
```
打开 <http://localhost:8080> 登录。首次运行时会自动创建管理员账号 `admin`,初始密码为**随机生成**并仅一次性打印在日志中——请立即记录并登录后修改(SECURITY_TODO #12,不再使用默认 admin/admin)。
> 前端资源全部本地化(`static/css/app.css` 为 Tailwind 静态构建产物,已提交)。修改 HTML 模板/Go 代码中的 Tailwind 类后,运行 `./scripts/build_tailwind.sh`(需 Node ≥ 18,npx 可用)重新生成并提交新产物;vendor 库更新同理重新下载到 `static/vendor/` 并提交。
## 配置
首次运行时,配置文件会自动生成:
| 平台 | 配置文件路径 | 数据存储路径 |
|---|---|---|
| Linux | `/etc/blog_go/config.yaml` | `/srv/blog_go/` |
| Windows | `./win/etc/blog_go/config.yaml` | `./win/srv/blog_go/` |
```yaml
# config.yaml
database:
type: sqlite # sqlite(默认)或 mysql
dsn: "" # MySQL 连接串,sqlite 模式下忽略
port: "8080" # Web 服务端口
path: ./win/srv/blog_go # 数据存储路径(数据库、上传文件)
secret: <自动生成> # Session 加密密钥
```
### 使用 MySQL
编辑 `config.yaml`
```yaml
database:
type: mysql
dsn: user:password@tcp(127.0.0.1:3306)/blog_go?charset=utf8mb4&parseTime=True&loc=Local
port: "8080"
```
先创建数据库:
```sql
CREATE DATABASE blog_go CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
```
## 项目结构
```
go_blog/
├── main.go # 入口,路由注册,中间件装配
├── config/
│ └── config.go # 配置加载 / 自动创建(区分操作系统)
├── models/
│ ├── user.go # 用户模型 + bcrypt
│ ├── article.go # 文章模型
│ ├── article_tag.go # 文章-标签关联
│ ├── article_view.go # 文章阅读统计
│ ├── attachment.go # 附件模型
│ ├── bot_detector.go # 机器人流量检测
│ ├── comment.go # 评论模型
│ ├── comment_config.go # 评论配置
│ ├── config_cache.go # 平台配置缓存
│ ├── db.go # GORM 初始化、自动迁移
│ ├── nav_link.go # 导航链接模型
│ ├── seed.go # 初始数据填充
│ ├── site_setting.go # 站点设置模型
│ ├── tag.go # 标签模型
│ └── upload_config.go # 上传配置
├── middleware/
│ └── auth.go # 登录验证、角色鉴权、语言检测
├── handlers/
│ ├── helpers.go # 公共工具函数
│ ├── home.go # 首页
│ ├── article.go # 文章详情、文章列表 API
│ ├── auth.go # 登录
│ ├── admin.go # 管理后台首页
│ ├── admin_comment.go # 评论管理
│ ├── admin_user.go # 用户管理
│ ├── admin_analytics.go # 阅读统计
│ ├── attachment.go # 附件上传/删除
│ ├── comment.go # 评论提交
│ ├── my_articles.go # 用户文章管理
│ ├── profile.go # 个人中心
│ ├── rss.go # RSS Feed
│ ├── settings.go # 站点/导航/上传/评论设置
│ └── upload_validator.go # 上传文件校验
├── i18n/
│ └── i18n.go # 中英文翻译映射 + Accept-Language 检测
├── static/
│ ├── css/app.css # Tailwind 静态构建产物(go:embed 编入二进制)
│ ├── css/input.css # Tailwind 构建输入(@tailwind 指令)
│ ├── css/markdown.css # Markdown 排版样式(go:embed 编入二进制)
│ ├── js/markdown.js # 前端 Markdown 渲染器(BlogMD
│ └── vendor/ # 本地化的第三方前端库(marked/DOMPurify/highlight.js/cropperjs/easymde
├── scripts/
│ └── build_tailwind.sh # 重新生成 Tailwind CSS(需 Node,见下)
├── templates/
│ ├── layouts/base.html # 公共布局(导航栏 + 头像下拉菜单 + 页脚)
│ ├── pages/
│ │ ├── home.html # 首页(瀑布流 + 无限滚动)
│ │ ├── article.html # 文章详情页
│ │ ├── login.html # 登录页
│ │ ├── register.html # 注册页
│ │ ├── profile.html # 个人中心
│ │ ├── search.html # 搜索页
│ │ └── 404.html # 404 页面
│ ├── admin/
│ │ ├── dashboard.html # 管理后台首页
│ │ ├── article_list.html # 文章列表
│ │ ├── article_create.html# 文章编辑
│ │ ├── comment_list.html # 评论审核
│ │ ├── user_list.html # 用户列表
│ │ ├── user_form.html # 用户表单
│ │ ├── analytics_views.html # 阅读统计
│ │ ├── settings_site.html # 站点设置
│ │ ├── settings_navlinks.html # 导航链接设置
│ │ ├── settings_upload.html # 上传设置
│ │ ├── settings_download.html # 下载设置
│ │ └── settings_comment.html # 评论设置
│ └── user/
│ ├── my_articles.html # 我的文章列表
│ └── my_article_form.html # 我的文章编辑
└── win/ # 运行时数据目录(Windows,自动创建)
├── etc/blog_go/
│ └── config.yaml
└── srv/blog_go/
├── blog.db
└── avatars/
```
## 路由
### 公开路由
| 方法 | 路径 | 说明 |
|---|---|---|
| GET | `/` | 首页 |
| GET | `/search` | 搜索页 |
| GET | `/api/articles` | 文章列表 API(无限滚动) |
| GET | `/rss``/feed` | RSS 订阅 |
| GET | `/article/:slug` | 文章详情 |
| POST | `/article/:slug/comments` | 发表评论 |
| GET | `/login` | 登录页 |
| POST | `/login` | 提交登录 |
| GET | `/register` | 注册页 |
| POST | `/register` | 提交注册 |
| POST | `/logout` | 退出登录 |
| GET | `/uploads/*` | 静态文件(头像、附件等) |
### 管理后台(需管理员权限)
| 方法 | 路径 | 说明 |
|---|---|---|
| GET | `/admin` | 管理后台首页 |
| GET | `/admin/articles` | 文章列表 |
| GET/POST | `/admin/articles/new` | 新建文章 |
| GET/POST | `/admin/articles/:id/edit` | 编辑文章 |
| POST | `/admin/articles/:id/delete` | 删除文章 |
| POST | `/admin/articles/attachments` | 上传附件 |
| POST | `/admin/articles/attachments/:id/delete` | 删除附件 |
| GET | `/admin/articles/:id/attachments` | 附件列表 |
| GET | `/admin/comments` | 评论管理 |
| POST | `/admin/comments/:id/approve` | 通过评论 |
| POST | `/admin/comments/:id/reject` | 拒绝评论 |
| POST | `/admin/comments/:id/delete` | 删除评论 |
| GET | `/admin/users` | 用户列表 |
| GET/POST | `/admin/users/new` | 新建用户 |
| GET/POST | `/admin/users/:id/edit` | 编辑用户 |
| POST | `/admin/users/:id/delete` | 删除用户 |
| GET | `/admin/analytics/views` | 阅读统计 |
| GET/POST | `/admin/settings/site` | 站点设置 |
| GET/POST | `/admin/settings/navlinks` | 导航链接设置 |
| GET/POST | `/admin/settings/upload` | 上传设置 |
| GET/POST | `/admin/settings/download` | 下载设置 |
| GET/POST | `/admin/settings/comments` | 评论设置 |
### 个人中心(需登录)
| 方法 | 路径 | 说明 |
|---|---|---|
| GET/POST | `/profile` | 编辑个人信息 |
| POST | `/profile/avatar` | 上传头像 |
| GET | `/my/articles` | 我的文章列表 |
| GET/POST | `/my/articles/new` | 新建文章 |
| GET/POST | `/my/articles/:id/edit` | 编辑文章 |
| POST | `/my/articles/:id/delete` | 删除文章 |
| POST | `/my/articles/attachments` | 上传附件 |
| POST | `/my/articles/attachments/:id/delete` | 删除附件 |
| GET | `/my/articles/:id/attachments` | 附件列表 |
## 用户角色
| 角色 | 个人中心 | 我的文章 | 管理后台 |
| --- | --- | --- | --- |
| `admin` | ✓ | ✓ | ✓ |
| `author` | ✓ | ✓ | ✗ |
## 许可证
MIT