weibaohui/user-management ↗★ 1
@weibaohui/user-management
dsh 插件 · 用户管理:给 dsh web 加登录门禁——未登录访问弹登录/注册页,首个注册者自动成为管理员;支持 TOTP 两步验证(验证器 App 扫码/手输密钥绑定);管理员可管理所有用户(删除、重置密码、角色调整、重置两步验证)并查看登录记录与访问记录,普通用户只能查看和修改自己的信息。
安装
npx -p @deepseek-ai/dsh dsh plugin --profile web add github:weibaohui/user-management说明文档
阅读完整 README ↗使用
- 装完重启后,通过网关访问:
https://:19843(浏览器首次会提示自签证书警告,按下方「HTTPS 证书」引导导入信任链后消失)——首个注册的账号就是管理员 - 管理入口:Web UI → 设置页 → 用户管理,七个页签:用户 / 登录记录 / 访问记录 / 操作日志 / IP 封禁 / HTTPS 证书 / 两步验证
- 管理员:用户表(新增用户 / 重置密码 / 角色调整 / 禁用启用 / 重置两步验证 / 删除)+ 四本审计/封禁台账 + 证书下载与信任引导 + 自己的两步验证
- 普通用户:个人信息卡 + 修改密码 + 两步验证 + 自己的登录记录
- 开启两步验证:设置页「两步验证」页签(或个人信息卡)→ 开启 → 验证器 App 扫二维码(或手动输入密钥)→ 输入 App 显示的 6 位动态码 → 绑定完成;之后登录输用户名密码,在「两步验证码」框填入 App 现查的 6 位动态码(未开启的账号留空即可,不会报错);勾选「记住用户名」后下次登录自动带出用户名,密码交给浏览器密码管理器记忆
- 侧栏左上角点头像/用户名:修改密码、退出登录
- 数据与审计文件都在
~/.dsh/user-management/(users.json/sessions.json/activity.jsonl/audit.jsonl/bans.json,0600 权限,原子写;审计账本滚动保留最近 5000 条) - IP 封禁按连接源地址(
remoteAddress)判定:本插件自带的网关不做代理改写,看到的即是客户端真实地址;若你在网关前面另加反代层,看到的将是反代的 IP
Remote Gateway 配置
v0.4 起,本插件自带 HTTPS 远程访问网关:dsh web 留在 loopback(127.0.0.1:3080),网关(独立 node:https 监听器)反代到它——网关是唯一对外入口,认证不可绕过。配置走 ~/.dsh/settings.yaml 的 user-management: 段(也支持设置页热生效)。
字段
| 字段 | 默认 | 说明 |
|---|---|---|
enabled | true | 关掉则不启动网关监听器 |
autoActivate | false | 注册审批开关。false(默认,审批制):自助注册的账号(首个管理员除外)直接落为禁用状态,注册页提示等待管理员审核,管理员在用户表点「启用」即完成审批;true:注册即激活、直接登录(历史行为) |
listenHost | 0.0.0.0 | 网关监听地址;127.0.0.1 仅本机可达 |
port | 19843 | 网关 HTTPS 端口 |
sites[] | [](=自动) | 站点白名单 + 证书;空 = 自动枚举本机所有 IP(含 sslip.io / nip.io 别名)。配了 sites 与自动列表合并而非替换:见下方「场景 3」 |
sites[].hosts | — | Host 白名单(域名/IP,支持 *.example.com 通配)。不带 cert/key 的 site 的 hosts 合并进自签 site(去重) |
sites[].cert / sites[].key | '' | PEM 文件路径(fullchain + privkey);配了则保留为独立 SNI site(按域名选证书),不配则按 hosts 自签 |
title | DSH 控制台 | 登录页标题 |
sessionDays / loginFailLimit / lockoutSeconds / maxBodyBytes | 7 / 5 / 60 / 16384 | 预留字段(当前未接线:会话由 store 管、body 上限在 API 内);TOTP 防爆破锁定内置为连续错 5 次锁 60 秒(内存态,重启清零) |
场景 1:零配置(推荐 · 私网)
不配 sites → 网关自动枚举本机所有非 loopback IP(IPv4 + IPv6,含 Tailscale)填进 hosts,并签发 100 年自签证书(SAN 覆盖这些 IP + localhost);listenHost 默认 0.0.0.0。打开 https://:19843 → 信任自签证书 → 注册/登录(首个访问者即管理员)。
场景 2:域名 + 证书
user-management:
listenHost: '0.0.0.0'
port: 19843
sites:
- hosts: ['dsh.example.com']
cert: '/etc/letsencrypt/live/dsh.example.com/fullchain.pem'
key: '/etc/letsencrypt/live/dsh.example.com/privkey.pem'
cert/key是 PEM 文件路径(fullchain + privkey,如certbot certonly -d申请);配了就加载你的证书,不配则按 hosts 自签。- 多域名走多项
sites(每项自己的hosts+cert+key),网关按 SNI 选证书。
场景 3:加一个不在本机网卡上的公网 IP(NAT)
服务器有个 NAT 进来的公网 IP(不在本机网卡上,不会被自动枚举到)。配 sites(不配 cert/key)即可把它合并进自签 site——本机 IP / LAN / Tailscale 访问不丢,公网 IP 也进自签证书 SAN:
user-management:
listenHost: '0.0.0.0'
port: 19843
sites:
- hosts: ['111.228.30.150'] # NAT 公网 IP,不带 cert/key -> 合并进自签 site
- 合并而非替换(v0.5.4+):配的 hosts 加到自动枚举列表里(localhost + 本机所有 IP + sslip/nip 别名 + 你配的 IP),自签证书 SAN 覆盖全部;带 cert/key 的 site 仍保留为独立 SNI site。
- 早期版本配
sites会替换自动列表,本机 IP 全丢 → 本地/LAN/Tailscale 访问被 421。v0.5.4 起改为加法合并。 - 公网 IP 走自签证书仍有「不受信任 CA」警告(导入信任链后消失);要真正零警告,给
.sslip.io等用 Let's Encrypt 签真证书(见「场景 2」写法)。
安全边界
- 零配置下首个访问者即管理员——仅适用于可信私网(Tailscale 等);公网暴露前请:配
sites白名单 + 用域名证书 + 先在 loopback(https://127.0.0.1:19843)注册首个 admin 再对外。 - 自签证书 100 年有效,持久化在
~/.dsh/user-management/certs/;改了 hosts/SAN 后删旧证书文件重启才会重签(否则复用旧证书保指纹稳定)。合并新增的公网 IP 同理:要让旧自签证书 SAN 补上该 IP,删localhost.crt/localhost.key重启即可重签。 - dsh web 始终留在 loopback,网关是唯一对外入口——直连 3080 绕不过认证。
场景 1:零配置(推荐 · 私网)
不配 sites → 网关自动枚举本机所有非 loopback IP(IPv4 + IPv6,含 Tailscale)填进 hosts,并签发 100 年自签证书(SAN 覆盖这些 IP + localhost);listenHost 默认 0.0.0.0。打开 https://:19843 → 信任自签证书 → 注册/登录(首个访问者即管理员)。