账号数据 - lmxdg/ZeroLogin GitHub Wiki

账号数据

ZeroLogin v1.1.0 提供两种账号存储后端,由 storage.type 决定:

后端 位置 适用场景
sqlite(默认) plugins/ZeroLogin/zerologin.db 一般服务器、账号较多
file(v1.0 后端) plugins/ZeroLogin/accounts/<UUID>.txt 少量账号、共享目录多服部署

SQLite 后端(默认)

单文件数据库 plugins/ZeroLogin/zerologin.db,WAL 日志模式。所有 SQL 在专用 IO 线程上串行执行,不阻塞服务端主线程。

表结构

CREATE TABLE accounts (
  uuid           TEXT    NOT NULL PRIMARY KEY,
  name           TEXT    NOT NULL,
  name_lc        TEXT    NOT NULL,           -- 小写玩家名,用于大小写不敏感查询
  password       TEXT    NOT NULL,           -- $pbkdf2$<迭代>$<盐>$<散列>
  registered_at  INTEGER NOT NULL DEFAULT 0,
  last_login_at  INTEGER NOT NULL DEFAULT 0,
  last_seen_at   INTEGER NOT NULL DEFAULT 0,
  login_count    INTEGER NOT NULL DEFAULT 0,
  auto_login_ips TEXT    NOT NULL DEFAULT '' -- 逗号分隔
);
CREATE UNIQUE INDEX idx_accounts_name_lc ON accounts(name_lc);

设计要点

  • uuid 主键:玩家改名只更新 name / name_lc,不丢数据
  • name_lc 唯一索引:按名字查询大小写不敏感,改名后按新名字仍可命中
  • 单行更新:写账号使用 INSERT ... ON CONFLICT(uuid) DO UPDATE,只改该玩家一行
  • 批量迁移单事务:迁移与导入走 saveAll,一次提交,失败整体回滚
  • 完整性自检:启动时执行 PRAGMA integrity_check,异常只告警不阻断启用
  • 驱动内联:sqlite-jdbc 打包时 relocate 到 dev.zerologin.libs.sqlite,不依赖服务端环境

备份

停止服务端后复制一个文件即可(若存在 -wal / -shm 侧文件,一并复制或先跑一次 checkpoint):

# 停止服务端后
cp plugins/ZeroLogin/zerologin* /backup/

file 后端

plugins/ZeroLogin/accounts/ 目录下每个账号一个文件,文件名即玩家 UUID,格式为可读的 key value 纯文本:

# ZeroLogin account record. Edit at your own risk.
schema 1
uuid 069a79f4-44e9-4726-a5be-fca90e38aaf5
name Steve
password $pbkdf2$120000$<盐(Base64)>$<散列(Base64)>
registered-at 1696000000000
last-login-at 1696000100000
last-seen-at 1696000100000
login-count 3
auto-login-ips 1.2.3.4,fe80::1
字段 说明
schema 数据格式版本
uuid 玩家 UUID(离线模式为按名字生成的离线 UUID)
name 最后观察到的玩家名,用于按名字查询
password PBKDF2 散列,格式见下表
registered-at 注册时间(毫秒时间戳)
last-login-at 最近登录时间
last-seen-at 最近在线时间
login-count 累计登录次数
auto-login-ips 自动登录 IP(逗号分隔,最多 5 个)

设计要点

  • 文件名为 UUID:玩家改名(含正版改名)不会造成主键冲突或数据丢失
  • 单账号单文件写入:登录高峰只重写对应玩家的小文件,不会整库重写
  • 原子写入:先写 .tmp 再原子替换,避免服务端崩溃导致文件损坏
  • 损坏容错:无法解析的文件会被安全跳过并记录警告,不会导致插件启动失败

口令散列格式(两种后端相同)

$pbkdf2$<迭代次数>$<盐(Base64)>$<散列(Base64)>
  • 算法:PBKDF2-HMAC-SHA256
  • 盐:随机 16 字节
  • 散列长度:256 位

后端切换与数据迁移

v1.0 升级到 sqlite

首次以 SQLite 启动且数据库为空时,插件自动导入 accounts/ 下的账号(非破坏式,原文件保留)。可用 storage.sqlite.import-file: false 关闭。

手动迁移

/zerologin migrate <from> <to> [force]
情形 行为
目标后端为空 直接导入
目标后端已有账号 中止并提示数量,需显式加 force
加了 force 先把目标后端现有账号导出为文本备份到 backups/migrate-<时间戳>/,再导入
同名但 UUID 不同 跳过该账号并汇报跳过数量
源后端为空 提示无可迁移数据

切换后端流程:停止服务端 → /zerologin migrate <当前后端> <目标后端> → 修改 storage.type → 启动服务端。


迁移到新服务器

  • sqlite 后端:停止两端服务端,把 zerologin.db(连同 -wal / -shm 侧文件)复制到新服相同位置即可
  • file 后端:把旧服的 plugins/ZeroLogin/accounts/ 复制到新服相同位置

离线模式下 UUID 由玩家名生成,只要玩家名不变,账号即可在新服继续使用。


多服共享

  • file 后端:可将多台服务端的 accounts/ 指向共享存储(NFS / SMB / 定期同步)。并发写入同一账号文件可能冲突,建议各服错峰。
  • sqlite 后端:单文件数据库适合「整库复制」,不适合多服并发读写同一文件。多服实时共享待后续 MySQL 后端。

手工编辑须知

⚠️ 不建议手工编辑账号数据。写入格式非法会导致该账号无法读取(file 后端会被安全跳过,SQLite 则可能破坏表约束)。

常见用途:

需求 sqlite 后端 file 后端
玩家忘记密码 DELETE FROM accounts WHERE name_lc = '<名字小写>' 删除该玩家的 .txt
清空某玩家 IP 白名单 把该行 auto_login_ips 置为 '' 删除文件中 auto-login-ips 行
手动迁移某个账号 SELECT * FROM accounts 导出后插入 复制对应 .txt 文件

手工操作数据库前请先停止服务端或做好备份。


相关: 安全说明 · 配置说明 · 常见问题

⚠️ **GitHub.com Fallback** ⚠️