Skip to content

让鼠钟等自家应用用鼠洞账号登录 - #347

Merged
JunieXD merged 1 commit into
mainfrom
first-party-oauth
Nov 6, 2026
Merged

JunieXD merged 1 commit into
mainfrom
first-party-oauth

Conversation

@JunieXD

@JunieXD JunieXD commented Nov 6, 2026

Copy link
Copy Markdown
Contributor

Refs #336

鼠钟一期要用鼠洞账号登录(总体设计 §6.7,接口 §8.3)。这是路线图第 3 步 OAuth 里自家应用的一半,建在 #346 成员的令牌上。授权服务器的元数据、Agent 注册、Agent 的授权页和设置页的接入命令,之后和 MCP 一起做:鼠钟用固定的地址就能连上,用不到它们。

改了什么

  • 新表 oauth_clients(自家应用,只存密钥的 SHA-256)、oauth_codes(授权码,只存 SHA-256),api_tokens 加上 client_id
  • 后台加「应用」页,站长登记、修改、换密钥和停用自家应用;密钥只显示一次。接口是 /admin/apps 的四个,停用时它的令牌都标为撤销
  • /oauth/authorize 页:自家应用不显示授权页
    • 登录了的直接带着 code、state 和 iss 跳回
    • 没登录的带 prompt=none 时带着 error=login_required 跳回,否则去 /login?next=…,用口令或 QQ 邮箱登录后回到授权页(链接登录在手机 QQ 里打开,回不到原来的浏览器)
    • 应用不存在、已停用或回调地址没登记时只在页面上报错,不跳回;其余错误按 OAuth 的格式带回给应用
  • 页面背后是 POST /api/v1/oauth/authorize,只能在网页上调
  • POST /oauth/token:用授权码、PKCE(S256)和密钥换令牌,密钥放在 Basic 认证里或表单里;返回和错误按 OAuth 的格式,带 Cache-Control: no-store。它在 CSRF 检查之前:应用的服务端调用时不带 Origin,靠密钥认
  • 授权码 5 分钟有效,换的时候在一条 DELETE … RETURNING 里取出,对不上也用掉了;封禁时删掉这个人没换的码,过期的每天清理
  • 每人在每个自家应用只有一个令牌,换新的时旧的作废。应用的令牌就是成员的令牌,范围、L3、限额和 90 天失效都照 接口认成员的令牌,给 Agent 和自家应用用 #346
  • GET /me 加上 restriction,鼠钟每小时用它刷新禁言状态
  • 操作日志加上「登录应用」「登记应用」「修改应用」「更换应用密钥」

怎么验证的

  • pnpm check 通过:类型检查、lint、格式和 412 个测试。新加的 server/modules/auth/oauth.test.ts 有 8 个:
    • 换令牌,再用令牌取 /me 和禁言状态
    • 授权码试一次就没了,回调地址和密钥对不上换不到
    • 没登录时 prompt=none 带着 login_required 跳回,不带返回 401
    • 应用和回调地址不对时不跳回,范围和 PKCE 不对时带着错误跳回
    • 每人一个令牌
    • 封禁时没换的码作废(去掉这处改动时这个测试会失败)
    • 停用后令牌失效,只有站长能管
  • pnpm e2e 通过,新加一个流程:站长在后台登记应用;登录了的打开授权页带着授权码回去;访客带 prompt=none 带着 login_required 回去,不带时去登录页
  • 在本地的开发版上走了一遍访客登录:打开授权页到登录页,拿口令,用 pnpm mock-bot code 确认,回到授权页,带着授权码跳回;再用 client_secret_post 换到令牌,用它取到 /me
  • pnpm phone-check 看过 /admin/apps、它的修改状态和授权页的报错,没有超出屏幕的元素

影响

  • 插件:不受影响,bot token 和代操作没有改
  • 前端:登录页认 next,只接受本站的路径
  • 鼠钟:上线后站长在后台登记鼠钟,把 client_id 和密钥填进鼠钟的 MOUSEHOLE_CLIENT_ID、MOUSEHOLE_CLIENT_SECRET

鼠钟一期要用鼠洞账号登录(总体设计 §6.7,接口 §8.3)。这是路线图第 3 步 OAuth 里自家应用的一半;元数据、Agent 注册和 Agent 的授权页之后和 MCP 一起做。

- 新表 oauth_clients、oauth_codes,api_tokens 加上 client_id
- 后台的「应用」页和 /admin/apps 接口:登记、修改、换密钥、停用,停用时它的令牌都作废
- /oauth/authorize 页:登录了的直接带着授权码、state 和 iss 跳回;没登录的带 prompt=none 时带着 login_required 跳回,否则先去登录页,用口令或 QQ 邮箱登录后回到这里
- POST /oauth/token:PKCE(S256)加密钥换令牌,密钥放在 Basic 认证里或表单里;授权码 5 分钟有效,试一次就没了;每人在每个应用只有一个令牌
- 封禁时没换的授权码也删掉,过期的每天清理
- GET /me 加上 restriction
@JunieXD
JunieXD merged commit 8193174 into main Nov 6, 2026
3 checks passed
@JunieXD
JunieXD deleted the first-party-oauth branch November 6, 2026 07:05
JunieXD added a commit to mousebaoyan/mouseclock that referenced this pull request Nov 6, 2026
鼠洞在 mousebaoyan/mousehole#347 实现了自家应用的 OAuth,鼠钟的登录不用改就能对上,文档里「还没实现」的说法去掉。

- 总体设计 §6.1、§17 去掉还没实现的说法,§18 待定事项删掉授权接口
- 开发约定写上怎么对着本地的鼠洞登录:鼠洞的开发版占着 5173,鼠钟换到 5174
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant