# 资源访问管理（sharelink）插件 · 配置指南与使用说明

> 适用版本：sharelink 1.2.x / Halo ≥ 2.22（已在 Halo Pro 2.25.4 实测；受保护链接自 1.2.0 起提供）
>
> 本文配合截图说明插件的功能、配置方法、使用流程和注意事项。
>
> 💬 遇到问题或有功能建议，欢迎到 [博客同名文章](https://blog.songshiyu.cn/archives/halo-bo-ke-zi-yuan-xia-zai-guan-li-cha-jian-pei-zhi-zhi-nan-yu-shi-yong-shuo-ming) 下方留言评论交流。

---

## 目录

1. [插件是做什么的](#一插件是做什么的)
2. [安装与启用](#二安装与启用)
3. [全局配置](#三全局配置)
4. [日常使用：创建下载资源](#四日常使用创建下载资源)
5. [受保护链接（超链接访问门禁）](#五受保护链接超链接访问门禁)
6. [访客看到的下载页](#六访客看到的下载页)
7. [下载统计与记录](#七下载统计与记录)
8. [文章引用扫描](#八文章引用扫描)
9. [邮箱验证详解](#九邮箱验证详解)
10. [防直链原理与边界](#十防直链原理与边界)
11. [注意事项汇总](#十一注意事项汇总)
12. [常见问题 FAQ](#十二常见问题-faq)

---

## 一、插件是做什么的

Halo 默认的附件可以通过 `/upload/文件名` 直链被任何人直接下载，无法统计、无法设防。本插件把「资源下载」变成可管理的一等公民：

| 能力 | 说明 |
|---|---|
| **下载链接管理** | 为每个资源生成 `/download/{slug}` 链接，粘贴到文章即可 |
| **下载统计** | 每个资源的下载次数、去重下载人数、逐条下载记录（时间/邮箱/IP/UA），可导出 CSV |
| **邮箱验证** | 按资源开关。访客需输入邮箱收取验证码，验证通过才能下载；验证过的邮箱长期免验证 |
| **防直链** | 注册为资源的附件，`/upload/**` 直链对外直接 404，文件真实地址不暴露 |
| **文章引用扫描** | 一键扫描全站文章，告诉你每个下载资源被哪些文章引用 |
| **受保护链接** | 给任意 http/https 超链接加访问门禁：邮箱验证放行、访问统计、真实地址隐藏 |

### 工作流程（一图流）

```
文章中粘贴 /download/xxx 链接
        │
        ▼
访客打开下载页（插件生成的独立页面）
        │
        ├─ 不需要验证：点击「立即下载」
        └─ 需要验证：输入邮箱 → 收验证码 → 填验证码
        │
        ▼
换取一次性下载令牌（默认 60 秒有效）→ 开始下载
        │
        ▼
后台记录一次下载（次数 +1，写入记录）
```

---

## 二、安装与启用

1. 进入 **Console → 系统 → 插件**，点击右上角 **「安装」**。
2. 选择 **「本地上传」** 上传 `sharelink-x.y.z.jar`（或「远程下载」粘贴 jar 地址）。
3. 安装后在插件列表找到 **「资源访问管理」**，点击启用。
4. 启用成功后，左侧菜单 **「内容」** 分组下会出现 **「资源访问管理」** 入口，一个页面内通过页签切换「下载资源」与「受保护链接」。

> ⚠️ **升级插件时的两个坑**（Halo 通用行为，非本插件问题）：
> - 用同名单 jar 覆盖安装时，会弹出「插件已存在，是否升级？」确认框，**必须点「确定」** 才会真正替换。
> - 后台界面静态资源按 `?version=` 缓存。**每次发布新版本必须递增版本号**，否则浏览器会继续使用旧界面。

---

## 三、全局配置

进入 **系统 → 插件 → 资源访问管理 → 设置**，有两个标签页。

### 3.1 基本设置

![基本设置](images/05-plugin-settings.png)

| 配置项 | 默认值 | 说明 |
|---|---|---|
| **下载令牌有效期（秒）** | 60 | 访客在下载页点击下载后，插件签发一次性下载令牌，需在此时长内开始下载。过期或已使用的令牌会跳回下载页重新获取，防止下载地址被传播复用 |
| **免验证资源下载去重窗口（分钟）** | 10 | 不需要邮箱验证的资源，同一 IP 在窗口内重复下载只计 1 次（防止刷新刷量），但下载行为本身不受限 |

### 3.2 邮箱验证

![邮箱验证设置](images/06-plugin-settings-email.png)

| 配置项 | 默认值 | 说明 |
|---|---|---|
| **验证码有效期（分钟）** | 10 | 验证码超过该时长未使用即失效 |
| **重发间隔（秒）** | 60 | 同一邮箱两次发码的最小间隔（下载页按钮有倒计时） |
| **同一邮箱每日发送上限** | 5 | 防止针对单个邮箱的轰炸 |
| **验证码最大错误尝试次数** | 5 | 连续输错超过该次数，验证码作废，需重新获取 |
| **同一 IP 每小时发送上限** | 20 | 防止单个 IP 批量发码 |
| **信任评论插件已验证的邮箱** | 开启 | 开启后，在评论组件中已验证过邮箱的访客，下载需要验证的资源时**无需再次验证**（需安装评论组件插件） |

> ⚠️ 邮箱验证依赖 Halo 的邮件通知能力。请确认 **设置 → 通知设置** 中已配置可用的邮件通知器（SMTP），否则验证码邮件发不出去。你的站点配置评论插件时应该已经配好。

---

## 四、日常使用：创建下载资源

进入 **内容 → 资源访问管理 → 下载资源** 页签，这里是所有下载资源的统一管理中心。

![下载管理列表](images/01-console-list.png)

### 4.1 新建资源

点击右上角 **「新建资源」**：

![新建资源弹窗](images/02-console-create-modal.png)

| 字段 | 说明 |
|---|---|
| **资源名称** * | 显示给访客的名称，也是下载文件的文件名（无扩展名时自动补上附件原扩展名） |
| **slug** * | 下载链接的标识，如填 `whitepaper-2024`，下载链接就是 `/download/whitepaper-2024`。仅限小写字母、数字、中划线。**创建后不可修改** |
| **描述** | 可选，显示在下载页标题下方 |
| **附件** | 点击「选择附件」从附件库选择（也可先上传新附件） |
| **需要邮箱验证** | 开启后访客必须验证邮箱才能下载 |
| **启用** | 停用后下载页和下载链接立即 404，但配置保留 |

保存后回到列表，点击该行的 **「复制」** 按钮即可拿到完整下载链接（含域名），粘贴到文章的任意位置（普通链接、按钮、卡片都可以）。

### 4.2 列表各列含义

- **邮箱验证**：该资源是否需要验证（需要 / 不需要）
- **启用**：开关即改即存
- **引用文章**：引用该资源下载链接的文章数，点击展开详情（见第八节）
- **下载数 / 下载人数**：累计下载次数 / 去重后的下载人数（验证资源按邮箱去重，免验证资源按 IP 去重）
- **操作**：记录（下载记录）、编辑、删除

> ⚠️ 删除资源会**连同其全部下载记录一起删除**，且下载链接立即失效，请谨慎操作。

---

## 五、受保护链接（超链接访问门禁）

除了附件下载，插件也可以给任意 **http/https 超链接**加一道访问门禁：访客先打开门禁页（需要时先完成邮箱验证），验证通过后才 302 跳转到真实地址。适合隐藏真实地址、按邮箱验证放行、统计访问量等场景。

| 能力 | 说明 |
|---|---|
| **访问门禁** | 为每个链接生成 `/link/{slug}` 门禁页，验证通过后才跳转 |
| **邮箱验证** | 按链接开关，与下载共用同一套验证码体系（验证过的邮箱两者通用） |
| **访问统计** | 每次跳转记录时间/邮箱/IP/UA，可导出 CSV；列表展示访问次数与去重访问人数 |
| **真实地址隐藏** | 门禁页不展示目标 URL，访客只有验证通过才会被跳转 |
| **文章引用扫描** | 一键扫描全站文章中出现的 `/link/{slug}` |

### 5.1 创建受保护链接

控制台 **「资源访问管理」→ 受保护链接** 页签 → **新建链接**：

- **链接名称**：访客在门禁页看到的标题
- **slug**：访问链接为 `/link/{slug}`，创建后不可修改；留空时会按目标链接自动生成建议值
- **目标链接**：验证通过后跳转的 http/https 地址，不会在门禁页展示
- **需要邮箱验证**：开启后访客需输入邮箱收取验证码（邮件模板与下载验证区分开，标题为「链接访问验证码」）
- **启用**：停用后门禁页 404

### 5.2 访客流程

```
文章中粘贴 /link/xxx（门禁页链接）
        │
        ▼
访客打开门禁页
        ├─ 不需要验证：点击「继续访问」
        └─ 需要验证：输入邮箱 → 收验证码 → 填验证码
        │
        ▼
换取一次性访问令牌（与下载共用「访问令牌有效期」设置）→ 302 跳转到目标地址
        │
        ▼
后台记录一次访问（次数 +1，写入访问记录）
```

> 与下载资源一样，访问令牌一次性有效，跳转后即失效；免验证链接同一 IP 在去重窗口内的重复访问只计 1 次。

---

## 六、访客看到的下载页

### 6.1 免验证资源

![免验证下载页](images/11-download-page-free.png)

页面展示资源名称和描述，点击 **「立即下载」** 即开始下载。简单直接。

### 6.2 需要邮箱验证的资源

![需验证下载页](images/12-download-page-verify-sent.png)

1. 输入邮箱地址；
2. 点击 **「发送验证码」**，按钮进入 60 秒倒计时，页面提示「验证码已发送，请查收邮件（10 分钟内有效）」；
3. 将邮件中的 6 位验证码填入，点击 **「立即下载」**。

**已验证过的邮箱**：下次再访问任何需要验证的资源时，输入邮箱后页面会提示「该邮箱已完成验证，可直接下载」，无需验证码（包括在评论区验证过的邮箱）：

![已验证邮箱直接下载](images/13-download-page-verified.png)

> 下载页为插件自带的独立页面，不依赖主题，任何主题下表现一致。

---

## 七、下载统计与记录

在资源列表点击 **「记录」**，打开该资源的下载记录：

![下载记录](images/03-console-records.png)

- 每条记录包含：**时间、邮箱**（免验证资源显示「匿名」）、**IP、User-Agent**；
- 支持分页浏览、删除单条记录；
- 点击 **「导出 CSV」** 可下载全部记录（带 BOM，Excel 直接打开不乱码）。

需要邮箱验证的资源，记录中可以看到具体是哪个邮箱下载的：

![验证资源的下载记录](images/03b-console-records-email.png)

**计数口径**（重要，避免误解数字）：

- 只有**真正开始下载**才计数：令牌核销成功且文件可输出时记 1 次，下载页浏览不计数、失败不计数；
- 免验证资源：同一 IP 在去重窗口（默认 10 分钟）内重复下载只计 1 次；
- 需要验证的资源：每次换令牌下载都计数（同一人多次下载会体现为次数 > 人数）。

---

## 八、文章引用扫描

资源多了之后最容易遇到的问题：「这个资源到底在哪些文章里用过？删了会不会有文章变死链？」

列表的 **「引用文章」** 列给出答案。点击数字展开：

![引用文章展开](images/04-console-references.png)

- 显示每篇引用文章的标题，点击 **「编辑器」** 直接跳转到文章编辑页，**「访问」** 打开前台文章页；
- 扫描结果缓存 5 分钟。刚改完文章想立即看到最新结果，点击页面顶部的 **「刷新引用扫描」** 强制重扫。

**扫描口径**：只统计**已发布**文章的正式内容中出现的 `/download/{slug}`；草稿、回收站文章、历史快照不计入。

---

## 九、邮箱验证详解

### 9.1 验证状态的来龙去脉

- 验证通过后，邮箱会被**永久登记**为「已验证」，之后下载任何需要验证的资源都无需再验证；
- 「已验证邮箱」有两个来源（可在设置中关掉第二个）：
  1. **本插件验证过的**：在下载页完成验证码验证的邮箱；
  2. **评论插件验证过的**（互认）：评论组件中「已验证邮箱」名单里的访客。开启「信任评论插件已验证的邮箱」后，在评论区验证过的读者下载时直接免验证，体验无缝。

### 9.2 安全设计（了解即可）

- 验证码 6 位数字，10 分钟有效，一次性使用，连续输错 5 次作废；
- 验证码比对使用恒时比较，防时序攻击；
- 发码有三级限流：同邮箱 60 秒重发间隔、同邮箱每天 5 封、同 IP 每小时 20 封；
- 邮件通过 Halo 通知中心发出，复用站点已有 SMTP 配置，插件不直接接触邮件密码。

---

## 十、防直链原理与边界

**原理**：插件在请求层面拦截 `GET/HEAD /upload/**`，如果目标附件已被注册为「启用的下载资源」，对外直接返回 404（就像文件不存在一样）；访客只能通过 `/download/{slug}` 下载页获取文件——文件由插件直接从服务器磁盘流式输出，**真实存储路径全程不暴露**。

**边界（务必了解）**：

| 场景 | 是否生效 |
|---|---|
| 本地存储策略的附件（你当前的使用方式） | ✅ 直链 404 |
| 外部对象存储（S3/OSS 等）的附件 | ❌ 无法拦截（文件不经 Halo 发出），但下载统计和邮箱验证仍正常 |
| 同一附件被文章当图片直接引用 | ⚠️ 会被一并拦截，图片变 404！ |

> ⚠️ **最重要的使用纪律**：不要把文章中需要**直接显示**的图片/附件注册为下载资源。注册即等于"此文件只能经下载页获取"。

---

## 十一、注意事项汇总

1. **图片与下载资源分离**：需要直接展示的图片不要注册为资源；建议下载类文件（zip/pdf 等）单独建一个附件分组管理。
2. **slug 创建后不可改**：改 slug 等于换链接，旧链接立即失效。如确需更换，新建资源并在文章里换链接（可用引用扫描找出所有旧链接位置）。
3. **删除资源会级联删除下载记录**。
4. **令牌有效期短是特性**：把 `/download/xxx/file?token=...` 发给别人是无用的（60 秒 + 一次性），分享请分享 `/download/xxx` 页面链接。
5. **大文件**：文件经 Halo 应用中转流式输出，不占内存，但占用服务器带宽；GB 级大文件建议评估带宽。
6. **引用扫描是按需的**：不实时监听文章变更，改完文章点「刷新引用扫描」或等 5 分钟缓存过期。
7. **升级插件**：确认弹窗要点「确定」；版本号每次递增；升级后界面异常先强刷浏览器。

---

## 十二、常见问题 FAQ

**Q：访客点下载没反应？**
A：下载令牌默认 60 秒有效，网络慢导致跳转超时时会自动回到下载页，重新点击即可。

**Q：收不到验证码邮件？**
A：① 检查 设置 → 通知设置 的 SMTP 是否可用（评论验证能用即正常）；② 检查垃圾邮件；③ 同一邮箱每天最多发 5 封、同一 IP 每小时 20 封，超限会提示稍后再试。

**Q：为什么图片附件注册成资源后文章里图片裂了？**
A：这是防直链的预期行为。把该图片从资源中移除（删除资源或换用专用下载文件），图片即可恢复显示。

**Q：下载数为什么比下载人数多？**
A：正常。同一个人多次下载，次数累加、人数去重。

**Q：对象存储附件能防直链吗？**
A：不能。防直链只对本地存储策略生效；但统计与邮箱验证对所有存储策略都有效。
