给教室里的 ClassIsland 管理界面加一把实体钥匙:配对一次 U 盘(或移动硬盘)之后, 老师插上盘、点一下「验证」就能解锁,学生碰不到密码。
它只做一件事,并把它做稳:
- 配对一次,插盘即解锁——不需要记密码、不需要重启、不依赖网络
- 密钥文件与「本机 + 这块盘 + 你的 Windows 账户」三重绑定——拷走、换盘、克隆都没用
- 每层校验都看得见——进度条与逐项状态告诉你走到哪一层,失败时能定位到具体环节
- 拔盘即失效——插件无状态,下次验证自然失败,不需要任何"还原"操作
更安全——这不是把"一个密码"换成"另一个密码",而是把验证依据放在攻击者拿不走的地方:
| 以往的 U 盘验证 | EasyAuth | |
|---|---|---|
| 密钥落盘形式 | 明文 GUID / 裸序列号哈希 | AES-256-GCM 加密,且与本机、磁盘、账户绑定 |
| 克隆检测 | 无(整盘复制照样解锁) | 每次成功计数 +1,旧克隆盘立即失效 |
| 多分区设备 | 不支持,插上就用不了 | 支持设备级同时校验(实验性) |
| 失败可诊断性 | 只有一个"验证失败" | 逐层状态 + 审计日志,能定位到具体环节 |
| 过程可追溯 | 无 | 配对/认证全程留痕(时间、盘符、序列号、失败层) |
U 盘解锁这条路,社区里已经有人先行趟过;我们站在已有的实现上, 把上面这些地方逐项补了起来。
更便携——教师只需要多带一支 U 盘,不需要多记一个密码:
- 单文件
.cipx,不装服务、不写系统目录、不需要管理员权限 - 无常驻进程、不开网络端口(课程查询 API 也只绑本机回环)
- 换电脑、换盘符都不影响识别——认的是磁盘序列号与卷标识,不是盘符
| 能力 | 说明 |
|---|---|
| 六层可插拔校验 | Windows 账户绑定(DPAPI,实验性)、token、磁盘序列号、卷标识、克隆计数、品牌提示,每层可单独开关 |
| 多分区同时校验 | ⛔ 实验性:可切「设备模式」,选设备而非选分区,该设备所有合格分区全部通过才算通过;特定设备下可能存不下凭据 |
| 克隆计数 | 每次成功解锁计数 +1,今天拷走的 U 盘明天就作废 |
| 审计日志 | 每次配对/认证结果都记录(时间、盘符、序列号、失败层与原因),可事后追溯 |
| 免管理员 | 查询走 WMI 与 mountvol,无需管理员权限,无常驻进程 |
| 纯插件 | 单个 .cipx,不装服务、不写系统目录 |
- 下载
ClassIsland.EasyAuth.cipx - ClassIsland → 设置 → 插件 → 从本地安装
.cipx - 重启 ClassIsland
把插件文件夹整个放进 ClassIsland 的 data\Plugins\cn.amengbro.easyauth\:
data\Plugins\cn.amengbro.easyauth\
├── ClassIsland.EasyAuth.dll
├── manifest.yml
└── ...
仅支持 Windows(ClassIsland 本体为 Windows 部署场景)。
- ClassIsland → 设置 → 管理凭据 → 在认证方式里添加「U盘密钥」
- 插上要当钥匙的 U 盘,在下拉框里选中它
- 点「读取」确认设备信息(序列号、卷标识都对得上)
- 按需勾选验证层 → 点「保存配对」→ 确定保存凭据
配对会在该分区上创建一个隐藏目录:
<U盘>\.EasyAuth\key.bin (目录带 隐藏 + 系统 属性,资源管理器里不可见)
- 插入 U 盘 → 打开管理凭据 → 选择「U盘密钥」
- 下拉框已自动预选配对分区(盘符变了也能认出,靠的是卷标识)
- 点「验证」→ 进度条与逐项状态会显示当前校验到哪一层
- 通过后按钮变成「继续」,点它完成验证
拔掉 U 盘无需任何「还原」操作——插件无状态,下次验证自然失败。
| 层 | 防的是 | 建议 |
|---|---|---|
| Windows 账户绑定 | U 盘被别人拿到后在别的 Windows 账户下使用 | ⛔ 实验性,可能无法使用:依赖 Windows DPAPI,需要对当前账户配置文件有读写权限。受限账户、域策略限制、容器/虚拟化环境下会直接失败。仅教师独占账户时才有额外保护;多账号共用几乎无增益 |
| token 校验 | 直接复制密钥文件 | 必开 |
| 磁盘序列号绑定 | 把 U 盘克隆/换成另一块盘 | 必开 |
| 卷标识绑定 | 同一块盘的其他分区顶替 | 必开 |
| 克隆计数 | 用旧快照复活过期克隆盘 | 必开 |
| 品牌提示 | ——(仅界面提示,不参与判定) | 可选 |
硬绑定层(token / 序列号 / 卷标识)至少要开一个,全关会被护栏拦下。
⛔ 尚未在所有设备上验证通过。 某些特定设备(多分区盘、盘符分配异常、含系统保留区的分区等)在配对时可能失败, 表现为点「保存配对」后凭据存不下去,或存下去了却解不开锁。 这类问题多半不是你操作不当,而是设备情况特殊。
建议:先用单分区模式验证通过,再切换到此模式;遇到存不下的设备换一支盘, 或直接改回单分区模式。
编辑凭据时勾选「多分区同时校验」,下拉框就从分区切换成设备:
- 选中设备 → 该设备所有合格分区全部校验通过才算认证通过
- 总容量 <32MB 或可用空间 <16MB 的分区会被自动丢弃(系统保留/恢复分区)
- 每个分区各存一份独立密钥,缺任一份都无法通过
能防:拿走 U 盘后拷贝密钥文件、克隆到别的盘、拷到同一块盘的其他分区、 用旧快照复活、把 U 盘拿到另一台电脑或另一个 Windows 账户下用。
防不了:能修改 ClassIsland 程序目录或 data 目录权限的人——他们可以直接改
Credentials.json 把认证方式删掉,这是 ClassIsland 本地模式本身的特性,任何插件都拦不住。
真正的边界在文件系统权限(目录 ACL 或集控模式)。
Q:提示「计数不符(密钥盘=x,本机=y)」? A:U 盘被整盘拷贝过导致计数落后。用原盘重新配对即可(计数会归零)。
Q:提示「卷标识不匹配」? A:选错了分区,或密钥文件来自同一块盘的其他分区。选回配对时的分区即可。
Q:换台电脑 U 盘还能用吗? A:不能。密钥与机器标识(MachineGuid)、磁盘序列号绑定,拷到别的电脑无法解密。
Q:教师把 U 盘弄丢了怎么办? A:用凭据里的其他认证方式(建议保留密码方式作兜底)解锁后重新配对。
git clone <本仓库>
cd ClassIsland.EasyAuth
dotnet build # 产出 cipx/ClassIsland.EasyAuth.cipx仓库自带控制台自测工具,不依赖 ClassIsland,直接在真实硬件上跑全部校验用例:
cd tools\DeviceProbe
dotnet run- 它没有花哨的桌面组件,不会在你的屏幕上飘任何东西
- 它不做「一键班级管理」,不替你排课,不替你装花里胡哨的挂件
- 它唯一的工作就是:在你点「验证」的那两秒里,确认插进来的是那支 U 盘
- 界面朴素得像一张 Excel——这是故意的。安全工具就该一眼看得懂,不该长得像游戏皮肤
- 你负责保管 U 盘,它负责不认错盘。各司其职
- 该插件未来可能用于 AmengTeachingService(开发中)相关软件的联动功能, 例如授课状态同步、远程提醒等
- 多分区同时校验与 Windows 账户绑定目前为实验性功能:前者尚未在所有设备验证通过(特定设备可能存不下凭据),后者依赖 DPAPI 权限(权限不足时可能无法使用)
EasyAuth 在 127.0.0.1:24721 起一个本地 HTTP 服务(只绑定回环,不对外),
让外部程序便捷获取课程信息、创建提醒。默认开启,端口与令牌可在插件目录的
api.json 里调整:
{ "Enabled": true, "Port": 24721, "Token": "" }Token 非空时,所有请求需带 Authorization: Bearer <Token>。
| 方法 | 路径 | 说明 |
|---|---|---|
| GET | /api/status |
插件与课表加载状态 |
| GET | /api/next-class |
下一节课是什么、还有多久 |
| GET | /api/class-plan?date=yyyy-MM-dd |
指定日期的课表与时间点 |
| POST | /api/reminder |
创建提醒(延时触发) |
| GET | /api/reminders |
待触发 / 已触发列表 |
| DELETE | /api/reminder/{id} |
取消指定提醒 |
{
"state": "OnClass",
"isInClass": true,
"isBreaking": false,
"isAfterSchool": false,
"hasNextClass": true,
"nextClass": {
"name": "数学",
"initial": "数",
"teacher": "王老师",
"startTime": "10:05:00",
"endTime": "10:50:00",
"durationSeconds": 2700
},
"currentClass": { "name": "语文", "teacher": "李老师", "startTime": "09:00:00", "endTime": "09:55:00" },
"secondsUntilNextClass": 0,
"secondsUntilBreak": 1200,
"timeUntilNextClass": "00:00:00",
"timeUntilBreak": "00:20:00"
}
secondsUntilNextClass语义:正在上课时为 0(要看还有多久下课请用secondsUntilBreak);未加载课表时为 0 且hasNextClass为 false。
三种定时方式,按优先级取第一个有效的:
| 字段 | 含义 | 示例 |
|---|---|---|
atTime |
绝对时间(推荐)。"HH:mm:ss" 当天时刻,已过则顺延到明天;也支持 ISO 8601 |
"10:05:00" |
delaySeconds |
相对延时秒数 | 600 |
| 都不传 | 立即触发 | —— |
展示选项(均可选,不传则用 ClassIsland 的默认设置):
| 字段 | 含义 | 默认 |
|---|---|---|
maskDurationSeconds |
**标题(遮罩)**停留秒数,优先于 durationSeconds |
5 |
overlayDurationSeconds |
**正文(浮层)**停留秒数,优先于 durationSeconds |
5 |
durationSeconds |
兜底时长,未单独指定标题/正文时两者都用它 | 5 |
effect |
是否启用强调特效(涟漪等) | ClassIsland 默认 |
sound |
是否播放音效 | ClassIsland 默认 |
soundPath |
自定义音效文件路径,留空用默认音效 | 空 |
speech |
是否语音播报 | ClassIsland 默认 |
topmost |
提醒时是否置顶主界面 | ClassIsland 默认 |
# 10:05 整点提醒:标题 3 秒、正文 12 秒、带音效、语音播报、置顶
curl -X POST http://127.0.0.1:24721/api/reminder \
-H "Content-Type: application/json" \
-d '{"title":"该上课了","message":"下节是数学,请准备课本",
"atTime":"10:05:00","maskDurationSeconds":3,"overlayDurationSeconds":12,
"sound":true,"speech":true,"topmost":true}'到时间后通过 ClassIsland 的通知系统弹出(EasyAuth 自带的提醒渠道)。到点即触发,精度 250ms。
一旦指定了
effect/sound/speech/topmost中任意一项,本次提醒会启用一套专用设置, 未指定的项取 ClassIsland 的默认值(特效默认开、音效/语音/置顶默认关)。
- 只监听
127.0.0.1,不可从局域网或外网访问 - 建议设置
Token;本机任意程序都能调用的接口,令牌是唯一的门槛 - 端口被占用时服务自动降级(不影响 ClassIsland 本体与认证功能),可在
audit.log看到API-START-FAIL
可以在凭据里添加多个「U盘密钥」项,每项各自独立配对、独立保存:
- 每个凭据记住自己的选择与配对(选择记录存在凭据自身,不共用)
- 同一支 U 盘不建议配对到两个凭据——两处会共用同一份密钥计数,互相顶替
- 推荐做法:一支盘对一个凭据;要给不同班级/不同用途配不同盘,就各建一个凭据
- ClassIsland 及其插件 SDK
- 社区中先行实现 U 盘认证的插件——为我们提供了参照
- 所有认真复现 bug 并附上崩溃报告和截图的人(尤其指出「多分区配完保存不进去」那位)
MIT · 仅供教学与校园管理使用,请同时遵守 ClassIsland 本体及其插件的许可条款。