- 版权类型
- 原创
- 版权链接
- #
- 前置组件
- LeviLamina https://github.com/LiteLDev/LeviLamina/
LegacyRemoteCall https://github.com/LiteLDev/LegacyRemoteCall
- 适配版本(基岩)
- 最新版本
WebHub
WebHub 为 Minecraft 基岩版服务器(LeviLamina)提供网页服务。玩家可通过浏览器查看服务器状态、参与服务器聊天、接收站内信;管理员可在网页端管理账号、在线会话与插件;第三方插件可将自身功能接入同一站点。编译日期: 2026/11/12
当前版本: v1.0.0
开发版本: v0.9.0
适配加载器: LeviLamina 26.51.x(BDS 1.26.51)
发行协议: 闭源
问题反馈群:1097933637
第三方插件接入方法见 SDK.md。
解决的问题
为服务器提供网页功能时,通常需要分别实现登录、权限、接口与页面框架;各插件的数据彼此独立,每增加一项功能都可能需要单独部署网页服务。WebHub 统一提供上述基础能力:| 需求 | 传统做法 | 使用 WebHub |
|---|---|---|
| 玩家在网页端查询商店 | 需另行部署网页插件 | 商店插件将页面注册至 WebHub,玩家在同一站点查看 |
| 玩家在网页端下架商品 | 网页端通常仅提供查看能力 | 商店插件声明相应操作,玩家可在网页端执行 |
| 多个插件共用访问入口 | 各插件需独立网址 | 顶部导航提供统一入口与登录 |
| 追溯操作责任人 | 需自行查阅日志 | 操作记录自动留存,支持按账号与时间检索 |
WebHub 的职责是托管、鉴权、分发与审计,不参与业务数据的加工。排行榜、统计聚合、赛季结算等由第三方插件实现,平台原样转发其返回的数据。
图片集
功能
面向玩家与访客的页面
- 概览:展示服务器状态卡(在线人数、流畅度、游戏内时间与天气、运行时长),以及服务器聊天栏与插件声明的信息块。TPS 数值与 10 分钟曲线收纳于「服务器性能」折叠区域,面向玩家仅呈现「流畅 / 一般 / 卡顿」三档。各卡片可由配置文件逐项开关,关闭后对应接口不再返回该数据。
- 配色:提供深色、浅色、暖黄、薄荷、天蓝五套方案。仅「深色」为深色底,其余四套为浅底换色相,适用于明亮环境。配色选择仅保存在本机(localStorage),不影响其他用户。
- 玩家:在线玩家名单与档案弹窗(本次上线时间、在线时长;管理员可查看关联账号)。XUID 与 UUID 不下发至网页端。
- 站内信:插件可向指定玩家投递通知,网页端支持收件、标记已读与清空。
- 我的:账号信息、当前启用的登录方式、退出登录,以及通知偏好(新消息提示、未读数是否合并为 9+)。
- 管理台:账号管理(角色调整、封禁与解封、踢下线、重置密码)、插件启停、内置动作面板、在线会话(可逐条踢出)、审计查询(按动作、操作者、对象与时间范围检索,支持导出 CSV)、运行统计(查询与动作分开计数),以及各插件开放的写操作清单。
面向插件的能力
| 通道 | 能力 | 说明 |
|---|---|---|
| 菜单 | 每个插件在顶部导航占独立入口 | 插件内多个菜单自动转为页内标签 |
| 页面 | 提交 HTML,由平台托管 | 沙箱 iframe,跟随本站配色,高度自适应 |
| 查询 | WEBHUB.call(path, opts) | 只读,适用于列表、详情与统计 |
| 动作 | WEBHUB.action(name, payload) | 写操作,须预先声明;受频率限制、并发限制与审计约束 |
| 数据 | KV / 集合 / 指标 / 事件 / 小对象 | 按命名空间隔离并设有配额,插件无需自行建表 |
| 概览信息块 | meta.tiles 声明 + kind: "tile" 取数 | 在概览页显示插件数据,可指定点击后跳转的页面 |
| 站内信 | notify(ns, xuid, title, body) | 向指定玩家投递通知 |
| 事件 | publish(ns, channel, payload) | 其他插件可按游标拉取 |
第三方插件只需实现一个 dispatch 函数,平台按 kind 区分查询与动作。
账号
- 玩家在游戏内输入 /web 即可自助注册、修改密码、查看账号,无需运维手工建号。
- 账号名固定等于游戏名(Xbox 名称),不可自定义。玩家改名后,下次进服自动同步;网页发言的署名始终取自游戏内名称。名称支持空格。若历史账号仍占用当前名称,本次注册或改名会将旧记录改为「名称#编号」——Xbox 名称全局唯一,同名记录必然已经失效。
- 账号与 XUID 一对一绑定;网页使用 Cookie 会话,有效期 7 天,修改密码后立即失效。
- 密码采用 PBKDF2-HMAC-SHA256 120000 轮加服务端 pepper;连续失败 5 次锁定 10 分钟。
- 三种角色:player / helper / admin,菜单、动作与接口均可按角色设置门槛。
登录方式
平台支持三种登录凭据。服务器决定开放哪些方式,玩家在游戏内决定自己启用哪些,两者取交集后生效:| 方式 | 凭据 | 说明 |
|---|---|---|
| 密码 | 用户名 + 密码 | 注册时可留空不设密码 |
| 本机网络 | 用户名 + 近期进服用过的 IP | 免密;仅限 player 角色 |
| 登录码 | 游戏内 /web 生成的 6 位数字 | 免密、一次性、默认 2 分钟;仅限 player 角色 |
- 免密方式免去记忆密码的负担,也避免密码在明文 HTTP 中传输,但其强度低于密码,因此角色上限固定为普通玩家,管理台必须使用密码登录。
- 默认仅开放密码(auth.methods: ["password"])。如需免密,可改为 ["password","ip"] 或 ["password","code"]。
- 同一出口 IP 下可能存在多个账号(网吧、家庭网络、运营商 NAT),因此「本机网络」登录仍需填写用户名,服务器不会依据 IP 自动选择账号。
- 修改密码不再要求原密码,且只能在游戏内进行;网页端已移除修改密码入口。账号的强身份由 Xbox 承担,网页端相应减少一条「取得会话即可改密」的路径。
快速开始
1. 安装
将发行包内的 WebHub 目录放入服务端 plugins 目录,使插件路径为 plugins/WebHub,启动服务器后控制台输出:[WebHub] v1.0.0 已启动 | 打开 http://127.0.0.1:8080/
首次启动会自动生成 config/webhub.json 与 data/webhub.db。
2. 首次配置
- 将 auth.pepper 改为随机字符串(保留默认值时启动日志会给出警告)。
- 公网部署时开启 trustProxy,并确保前方反向代理设置了 X-Forwarded-For。
- 确认 devRoutes 为 false。
- 按第 3 步注册本人账号,将该账号名称填入 initialAdmin 并重启插件,该账号即为管理员(详见「角色配置」)。
3. 玩家注册
玩家进服后输入 /web,选择「注册账号」。账号名自动取游戏名,玩家仅需设置密码。服务器已开放免密方式时,密码可以留空,此时只能通过本机网络或登录码进入网页。4. 接入插件
在插件的 onServerStarted 中完成注册、提交页面并导出 dispatch:const meta = { ns: "MyShop", name: "商店", scopes: ["rpc"],
menus: [{ path: "shop", title: "商店", role: "player", sort: 10, page: "shop" }],
// 可选:在概览页显示信息块,点击后跳转到 page
tiles: [{ id: "today", title: "今日成交", page: "shop", role: "player", sort: 10 }] };
ll.imports("WebHub", "register")(JSON.stringify(meta));
ll.imports("WebHub", "page")("MyShop", "shop", "商店", html);
ll.exports(dispatch, "MyShop", "webhub.dispatch");
完整的声明格式、动作定义、信息块取数与页面样式约定见 SDK.md。
权限模型
| 层 | 配置方 | 说明 |
|---|---|---|
| 登录 | — | 大部分读接口对访客开放,写接口一律要求登录 |
| 角色 | 平台 | player < helper < admin;菜单与动作各自声明最低角色,调整方式见「角色配置」 |
| 能力 | 插件声明 | scopes 决定插件可调用哪些平台函数(KV、事件、站内信等) |
| 资源归属 | 插件自身 | 平台只识别请求者的角色,不判断其与业务资源的关系 |
| 数据面 | 平台 | /api/v1/data/** 全部要求 admin,供运维与外部集成使用 |
角色配置
三种角色由低到高依次为 player(普通玩家,注册时默认)、helper(协助)、admin(管理员)。插件菜单、插件动作与平台接口均可声明最低角色要求;管理台与 /api/v1/data/** 仅限 admin。首位管理员
先在游戏内通过 /web 注册账号,然后打开 config/webhub.json,将账号名填入 initialAdmin:"initialAdmin": "账号名",
重启插件后,启动日志会输出 初始管理员 账号名:1 个账号已设为 admin,刷新网页即可看到管理台。该配置每次加载都会确保此账号为 admin;配置完成后可以清空,保留亦不影响运行。
调整其他账号角色
两个入口效果相同,均会写入审计并向当事人发送站内信:- 网页:管理台 → 账号 → 操作列的角色下拉框,选择「玩家 / 协助 / 管理员」后立即生效。该操作调用 POST /api/v1/actions/set_role(参数 {"username": "...", "role": "admin"})。
- 游戏内:管理员输入 /web,选择「管理员:授予角色」,选择在线玩家与目标角色。该方式无需打开浏览器,但对方须已注册网页账号。
应急处理:直接修改数据库
不便重启修改配置时,可停服后直接修改数据库,修改完成后启动服务器即可(账号名需为小写):python -c "import sqlite3; d=sqlite3.connect('plugins/WebHub/data/webhub.db'); d.execute(\"UPDATE accounts SET role='admin' WHERE username_lc=?\", ('账号名小写',)); d.commit()"
角色在每次请求时从数据库读取,修改后刷新网页即生效,无需重启;仅 initialAdmin 需要重启,因为配置只在加载时读取一次。
部署
plugins/WebHub/├── WebHub.dll
├── manifest.json
├── config/webhub.json # 配置(首次启动生成)
├── data/webhub.db # SQLite(WAL)
├── data/blobs/ # 小对象内容
├── data/backups/ # 自动备份,默认每 6 小时,保留 7 份
└── web/ # 前端,可直接修改
关键配置
修改配置后需重启插件,配置只在加载时读取一次。升级时无需更换配置文件:插件加载时会将新版本新增、而现有文件中缺失的字段按默认值补写,已有取值保持不变。
| 字段 | 默认 | 说明 |
|---|---|---|
| bind / port | 0.0.0.0 / 8080 | 监听地址 |
| siteName | 空 | 完整站点名(顶部导航、登录框、浏览器标题),填写后原样显示;优先级高于 servername |
| servername | 空 | 服务器名,填写「明月」则显示「明月服务器网站」;siteName 非空时以它为准 |
| initialAdmin | 空 | 初始管理员的账号名;每次加载将该账号设为 admin,留空则不处理 |
| httpWorkers | 4 | HTTP 工作线程数 |
| trustProxy | false | 位于反向代理之后时从 X-Forwarded-For 取真实 IP |
| requireAuthForRead | false | 为 true 时概览与玩家列表也要求登录(公网建议开启) |
| devRoutes | false | /debug/* 自检路由,生产环境必须关闭 |
| auth.pepper | change-me-please | 必须修改,且与数据库分开存放 |
| auth.minPassword | 8 | 密码最短长度 |
| auth.methods | ["password"] | 允许的登录方式:password / ip / code,可多选 |
| auth.ipTrustDays | 7 | 游戏登录 IP 作为凭据的有效期(天),0 表示不信任 |
| auth.codeTtlSeconds | 120 | 一次性登录码有效期(秒) |
| limit.*PerMin | — | 读 240 / 写 120 / 登录 10 / 查询 120 / 动作 30 |
| quota.* | — | 按命名空间隔离的存储配额 |
| rpc.timeoutMs / rpc.actionTimeoutMs | 3000 / 5000 | 查询与动作超时(毫秒) |
| rpc.maxConcurrent / rpc.actionMaxConcurrent | 4 / 2 | 每个插件的查询与动作并发上限 |
| backup.* | 6 小时 / 7 份 | 自动备份周期与保留份数 |
| display.* | 全 true | 概览逐项开关:在线玩家 / TPS / 运行时长 / 游戏时间 / 天气 / 聊天 / 信息块 |
| chat.maxLines | 20 | 内存中保留的最近聊天条数(不写入数据库) |
| chat.allowSend | true | 是否允许网页发言;格式为 §e[网页]§r <玩家名> 内容 |
| chat.publicRead | false | 为 false 时查看聊天需登录 |
| chat.mode | both | 聊天来源:event / forward / both。安装接管聊天的插件时改为 forward |
| chat.dedupSeconds | 5 | 事件与转发重复时的去重窗口(秒) |
| chat.perMin / chat.maxLength | 6 / 200 | 发言频率(每 IP 每分钟)与单条字节上限 |
| tiles.ttlMs | 15000 | 信息块取数缓存时长;personal 信息块不缓存 |
| tiles.maxTiles | 8 | 单个插件可声明的信息块数量上限 |
反向代理
平台不提供 TLS,公网部署应使用 Nginx 或 Caddy 终结 TLS:location / {
proxy_pass http://127.0.0.1:8080
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_read_timeout 30s;
}
同时将 trustProxy 设为 true,否则频率限制会将所有请求计入代理 IP。
安全设计
| 面 | 措施 |
|---|---|
| 密码 | PBKDF2 120k 轮加 pepper;失败锁定;恒定时间比较 |
| 会话 | HttpOnly + SameSite=Lax Cookie;改密或停用后立即失效 |
| 注入 | 全部使用预准备语句;排序字段白名单;LIKE 通配符转义 |
| XSS | 前端不使用 innerHTML 拼接用户数据;插件页运行于 CSP sandbox 的 opaque origin |
| 越权 | 每个接口显式声明最低角色;动作仅接受插件声明过的名称与角色 |
| 滥用 | 按 IP 的令牌桶(登录 10/min、动作 30/min);配额硬上限;请求体与页面大小上限 |
| 信息泄露 | 玩家列表不含 XUID/UUID;账号接口仅返回脱敏字段;插件只能访问自身命名空间 |
| 审计 | 管理操作、插件动作、网页发言全量记录,失败同样记录,密码类字段自动脱敏 |
| 免密登录 | 默认关闭;仅限 player;「本机网络」要求账号名与近期进服 IP 同时匹配,并受 auth.ipTrustDays 限制;登录码一次性、短时效,生成新码即作废旧码 |
| 身份冒充 | 账号名固定取 Xbox 名称且不可自定义;进服时按 XUID 同步,网页发言署名取游戏内名称 |
| 聊天 | 仅在内存保留最近若干条(不写入数据库);网页发言去除 § 颜色码与换行,每 IP 每分钟 6 条 |
文档
| 文件 | 内容 |
|---|---|
| SDK.md | 第三方插件接入:声明、页面、dispatch、动作、错误码、配额 |
| Changelog.md | 发行版本的变更记录 |