跳到主要内容

远程访问认证

CountBot 支持通过非本地 IP 远程访问 Web UI,同时通过强制认证系统保证安全性。

::: warning 桌面预编译版限制 桌面预编译版(如 .exe 安装包)不支持通过环境变量修改监听地址,无法开启远程访问模式。

如需远程访问,请使用源码版本。 :::

概述

CountBot 默认通过 127.0.0.1:8000 本地访问,无需登录认证。当通过非本地 IP 访问时,系统自动启用认证。

核心安全特性

  • 首次设置管理员账号只能在服务所在机器本地完成,或通过 /setup/<随机码> 远程初始化
  • 密码要求:至少 8 位,包含大写字母、小写字母和数字
  • 登录态通过 Cookie CountBot_token 维持
  • 本地访问 (127.0.0.1) 不受影响
  • 渠道消息(微信/飞书/钉钉等)不受影响

本地 vs 远程检测

本地请求判定

以下来源视为本地请求,无需登录:

  • 127.0.0.1
  • localhost
  • ::1(IPv6)
  • 0.0.0.0

远程请求判定

除本地请求外,所有其他来源均视为远程请求,需要登录认证。

注意:通过反向代理访问时,代理会转发 X-Forwarded-For 头,系统据此识别客户端真实 IP,不会视为本地请求。

首次设置

首次设置页面

首次访问时,系统自动跳转到 /first-setup 页面,要求设置:

  1. 管理员账号:用户名,建议使用邮箱地址
  2. 管理员密码:至少 8 位,包含大写字母、小写字母和数字
  3. 确认密码:与管理员密码一致

设置流程

用户访问 /first-setup

验证密码规则(长度 ≥ 8,包含大写、小写、数字)

保存凭据到数据库

设置登录 Cookie

跳转到 / 页面

安全机制

  • 密码在数据库中加密存储(bcrypt)
  • 首次设置完成后,设置页面不再显示
  • 管理员凭据用于后续远程访问登录

远程初始化

场景

当 CountBot 部署在远程服务器,无法直接本地访问时,可通过 /setup/<随机码> 完成首次设置。

初始化流程

python start_app.py

生成 8 位随机字母码

打印启动信息(包含 setup URL)

等待 15 秒

打开浏览器(本地)

打印内容示例:

远程首次初始化入口:将此路径拼接到上方 Network 地址后访问
(有效期 30 分钟,初始化成功后立即失效)
→ /setup/akLRzvlW

安全机制

  1. 一次性验证:首次使用后立即删除随机码
  2. 随机性:8 位字母组合,足够抵抗普通扫描
  3. 超时保护:默认 30 分钟,超时后自动失效
  4. 本地优先:本地访问不受限制

示例

# 启动 CountBot(开启远程访问)
COUNTBOT_HOST=0.0.0.0 python start_app.py

# 输出包含 setup URL,拼接 Network 地址访问
# 例如:http://192.168.1.100:8000/setup/akLRzvlW
# 在浏览器中打开该 URL
# 设置管理员账号和密码
# 设置完成后使用 /login 页面登录

登录系统

登录页面

远程访问时,系统自动跳转到 /login 页面。

登录流程

用户访问远程页面

检测需要登录

重定向到 /login?redirect=<原URL>

用户输入凭据

验证成功:设置 Cookie 并跳转到原页面
验证失败:显示错误信息
  • Cookie 名称:CountBot_token
  • 有效期:365 天
  • 安全属性:Secure=False, HttpOnly=True, SameSite=Lax
  • 路径:/

登出

点击页面右上角的 "Logout" 按钮即可登出。登出后 Cookie 被清除,下次访问远程页面时需要重新登录。

认证中间件

实现

认证通过 FastAPI 中间件实现,对所有非本地请求进行检查。

绕过页面

以下页面无需登录:

  • /login - 登录页面
  • /first-setup - 首次设置页面
  • /setup/* - 远程初始化页面
  • /api/login - 登录 API
  • /api/first-setup - 首次设置 API
  • /api/setup/init - 远程初始化 API
  • /api/setup/verify - 远程初始化验证 API
  • /health - 健康检查
  • /api/health - 健康检查 API
  • /ws - WebSocket 连接(由独立逻辑处理)

WebSocket 认证

WebSocket 连接通过 token 查询参数传递认证令牌:

ws://example.com/ws?token=<CountBot_token>

前端在连接时自动附加 Cookie 中的令牌。

远程初始化安全

随机码生成

使用 secrets.token_hex(32) 生成 64 位随机码,密码学安全。

数据库存储

随机码加密存储在 settings 表中:

keyvalueencrypted
setup_init_code_hashbcrypt.hash(随机码)True

验证流程

GET /setup/<随机码>

从数据库读取 setup_init_code_hash

bcrypt.checkpw(随机码, hash)

验证成功:渲染设置页面,存储 setup_code_verified=true
验证失败:返回 404

一次性使用

验证成功后随机码从数据库删除:

del settings["setup_init_code_hash"]
del settings["setup_init_code_verified"]

密码安全

密码规则

  • 最小长度:8 位
  • 必须包含:大写字母、小写字母、数字
  • 正则:^(?=.*[a-z])(?=.*[A-Z])(?=.*\d).{8,}$

密码存储

密码使用 bcrypt 哈希:

from passlib.context import CryptContext

pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
hashed_password = pwd_context.hash(password)

密码验证

pwd_context.verify(password, hashed_password)

环境变量

认证系统不使用专用环境变量。本地/远程检测基于请求来源 IP。

如需修改服务监听地址和端口:

变量默认值说明
COUNTBOT_HOST127.0.0.1监听地址
COUNTBOT_PORT8000监听端口

详见部署与运维

渠道访问

渠道消息通过独立 API 路由处理,不受远程访问认证影响:

  • /api/telegram/webhook
  • /api/feishu/webhook
  • /api/dingtalk/webhook
  • /api/wecom/webhook
  • /api/weibo/webhook
  • /api/xiaozhi/webhook
  • /api/qq/webhook
  • /api/wechat/webhook

这些路由由 ChannelManager 注册,在认证中间件检查前直接返回。

故障排查

首次设置页面不显示

  • 确保数据库为空
  • 检查数据库文件 data/countbot.db

登录失败

  • 确认管理员账号和密码正确
  • 检查浏览器 Cookie 是否被阻止

远程初始化 URL 未显示

  • 检查启动日志
  • 确保数据库为空且未设置管理员

安全最佳实践

  • 完成远程初始化后立即删除启动日志中的 setup URL
  • 不要在公开渠道分享 setup URL 或管理员凭据
  • 使用反向代理时配置 HTTPS
  • 定期更新 CountBot 到最新版本
  • 设置强密码并妥善保管

相关文件

文件说明
backend/middleware/auth.py认证中间件
backend/api/auth.py认证 API
backend/database.py数据库配置
backend/app.py应用初始化
start_app.py启动脚本