
















保险箱插件为 Halo 站点提供基于规则和密码的资源访问保护。命中规则后,访客会先进入解锁页,密码验证通过后插件写入带有效期的 HttpOnly Cookie,并自动跳回原资源。
*、**、? 通配符。plugin:safebox:rule:view、plugin:safebox:rule:manage 控制;公开解锁接口自动授权匿名访问。| 类型 | 值 | 适用场景 | 说明 |
|---|---|---|---|
| 附件 | ATTACHMENT |
私密图片、PDF、压缩包等上传文件 | 只保护 /upload 下的资源。 |
| 指定路由 | ROUTE |
会员页、下载页、活动页等前台路径 | 保护命中的前台路由,不影响 Halo 管理后台和插件接口。 |
| 整站私密 | SITE |
临时闭站、内部站点、密码访问站点 | 默认按 /** 匹配,可通过排除路径放行部分页面。 |
插件内置排除以下路径,避免把后台、接口、登录页和静态资源锁死:
/safebox/**
/apis/**
/console/**
/uc/**
/login
/logout
/oauth2/**
/actuator/**
/plugins/**
/themes/**
/assets/**
| 字段 | 说明 |
|---|---|
| 规则名称 | 控制台展示名称,也是解锁页默认标题来源。 |
| 规则说明 | 解锁页说明文案;为空时使用默认提示。 |
| 保护对象类型 | ATTACHMENT、ROUTE、SITE 三选一。 |
| 保护路径 | 一行一个路径模式,也支持用逗号分隔。建议填写以 / 开头的 pathname,不要填写完整 URL。 |
| 排除路径 | 命中这些路径时直接放行,常用于整站私密下放开公开页面。 |
| 访问密码 | 创建时必填;更新时留空表示保留原密码。密码以加盐 SHA-256 哈希保存。 |
| 优先级 | 数字越大越先匹配。相同优先级下,路径越具体越先匹配。 |
| 解锁有效期 | 单位秒,最小 60 秒,默认 3600 秒。 |
| 启用状态 | 停用后该规则不参与命中。 |
插件会从启用规则中选择最终命中的一条规则:
/upload 下的资源。/docs 会命中 /docs/a.pdf。priority 倒序排列。priority 相同时,路径匹配越具体越优先。访问行为:
GET、HEAD 请求命中规则且未解锁时,会以 303 See Other 跳转到 /safebox/unlock?path=...。GET、HEAD 请求命中规则且未解锁时,会返回 401 Unauthorized。ttlSeconds。常用示例:
/upload/private/report.pdf # 保护单个附件
/upload/private/** # 保护整个附件目录
/vip # 保护 /vip 及其子路径
/** # 整站私密
/public/** # 可作为整站私密的排除路径
/safebox/unlock,验证成功后自动回到原资源。如果只想保护某个附件,也可以在 Halo 附件列表中打开该附件的操作菜单,选择「新增保险箱规则」。附件没有固定访问地址时不能创建规则,因为插件需要稳定的访问路径才能进行匹配。
主题不需要主动判断资源是否受保护,访问拦截由插件的 WebFilter 统一处理。主题侧主要做一件事:按自己的设计覆盖解锁页模板。
受保护资源会统一跳转到:
/safebox/unlock?path=/upload/example.png
主题可以在当前主题的模板目录中提供 safebox-unlock.html 覆盖插件内置解锁页;未提供时使用插件内置模板。
templates/
safebox-unlock.html
解锁表单必须使用 POST 提交到 unlockAction,并保留 path、password 两个字段:
<!doctype html>
<html lang="zh-CN" xmlns:th="https://www.thymeleaf.org">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title th:text="${displayName} + ' - 访问验证'">访问验证</title>
</head>
<body>
<main>
<h1 th:text="${displayName}">受保护资源</h1>
<p th:text="${description}">该资源已开启访问保护,请输入密码后继续访问。</p>
<p th:if="${error != null and error != ''}" th:text="${error}">密码不正确。</p>
<form method="post" th:action="${unlockAction}">
<input type="hidden" name="path" th:value="${path}">
<label for="password">访问密码</label>
<input id="password" name="password" type="password" autocomplete="current-password" required>
<button type="submit">解锁资源</button>
</form>
</main>
</body>
</html>
可用模板变量:
| 变量 | 说明 |
|---|---|
displayName |
匹配规则名称;为空时为 受保护资源。 |
description |
匹配规则说明;为空时为默认提示。 |
path |
待解锁资源路径,验证通过后会跳回该路径。 |
error |
错误文案;密码错误时为 密码不正确。。 |
unlockAction |
解锁表单提交地址,当前为 /apis/public.safebox.muyin.site/v1alpha1/unlock。 |
unlockPagePath |
固定解锁页路径,当前为 /safebox/unlock。 |
rule |
匹配到的 SafeBoxRule 对象,可读取 rule.spec.displayName、rule.spec.description 等字段。 |
注意事项:
path 和 password 少一个都无法解锁。>= 2.20.14# 启动 Halo 开发服务器
./gradlew haloServer
# 修改后热重载插件
./gradlew reload
# 开发前端资源
cd ui
pnpm install
pnpm dev
./gradlew build
构建完成后,可以在 build/libs 目录找到插件 JAR 文件。
./gradlew test
cd ui
pnpm test:unit
pnpm type-check
GPL-3.0 © Lywq
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。