fix(openai): /openai/responses/stream 加每用户限流(INV-006) - #41
Merged
Conversation
该端点烧付费 LLM 额度,此前只有 @SaCheckLogin 无限流——登录用户可绕过 Next.js 层的 Upstash 限流直接 curl 后端刷额度(Caddy 裸透传不过滤路径)。 - 新增 OpenAiStreamRateLimiter:Caffeine 每用户固定窗口计数,默认 10 次/分钟(OPENAI_STREAM_RPM 可配),超限 429。进程内存级即可 (单实例部署;横向扩容时换 Redis 计数,接口不变) - 控制器在流式处理前 checkOrThrow(StpUtil.getLoginIdAsLong()) - SECURITY.md 新增 INV-006「付费 LLM 端点必须每用户限流」+ 3 个回归 测试(超限 429 / 用户隔离 / 窗口过期恢复,假 Ticker 驱动) 全量 246 测试通过。
longsizhuo
added a commit
that referenced
this pull request
Jul 19, 2026
xhigh review (PR #43) 的已确认问题: - init.sql 补 user_identities 表:三处 schema 同步惯例(INV-004 教训), 否则 docker-compose 起的库缺表,M1 登录 500 - ADR 的 state 不变量 INV-006 → INV-007:INV-006 已被 PR #41 限流占用 - 回填注释澄清边界:依赖 SPRING_SQL_INIT_MODE=always;只治行缺失不治值变化; M2 解绑 github 须同时清 github_id 列,否则重启静默复活已撤销绑定 - 仓库层 provider 归一化小写:JustAuth source 名大写,不归一化查询侧静默查空 - insert() javadoc 声明忽略 linkedAt/lastLoginAt(由 DB default 生成) - 幂等测试改从 classpath 的 schema.sql 机械提取回填语句,不再手抄副本 全量 252 测试通过。
longsizhuo
added a commit
that referenced
this pull request
Jul 19, 2026
* feat(usercenter): M0 多 provider 身份表 user_identities + 幂等回填 RFC involutionhell-backend#42 / ADR-001 的第一阶段,纯增量零行为变化: - user_identities 表:UNIQUE(provider,provider_user_id) + UNIQUE(user_id,provider) + provider 小写 CHECK + FK ON DELETE CASCADE - 启动回填存量 github_id → provider='github' 行,ON CONFLICT DO NOTHING 保幂等 - UserIdentity model + JdbcUserIdentityRepository(沿用 JDBC 惯例) - 5 个仓库测试覆盖两条 UNIQUE、级联删除、回填幂等 - ADR-001(OKF frontmatter)记录设计决策与 OAuth state 防护协议 生产数据干跑验证:51 个 github_id 账号,0 重复 / 0 非数字 cast,回填无冲突。 全量 251 测试通过。 * fix(usercenter): 处理 M0 review 反馈 xhigh review (PR #43) 的已确认问题: - init.sql 补 user_identities 表:三处 schema 同步惯例(INV-004 教训), 否则 docker-compose 起的库缺表,M1 登录 500 - ADR 的 state 不变量 INV-006 → INV-007:INV-006 已被 PR #41 限流占用 - 回填注释澄清边界:依赖 SPRING_SQL_INIT_MODE=always;只治行缺失不治值变化; M2 解绑 github 须同时清 github_id 列,否则重启静默复活已撤销绑定 - 仓库层 provider 归一化小写:JustAuth source 名大写,不归一化查询侧静默查空 - insert() javadoc 声明忽略 linkedAt/lastLoginAt(由 DB default 生成) - 幂等测试改从 classpath 的 schema.sql 机械提取回填语句,不再手抄副本 全量 252 测试通过。 * fix(db): 保证全新贡献者能干净启动——init.sql 补齐 user_accounts 列 + 去掉 never 建议 M0 的 user_identities 回填读 user_accounts.github_id,但 docker/init-db/init.sql 建的 user_accounts 只有 7 列、缺 github_id/avatar_url/email/preferences,schema.sql 的 CREATE TABLE IF NOT EXISTS 又补不上已存在表的列——全新 docker 卷首启时回填 直接 column "github_id" does not exist 崩,后端起不来(既有 bug:github 登录 INSERT 本就缺列,M0 把它升级成硬崩)。 - init.sql 的 user_accounts 补齐到与 schema.sql 一致 - .env.example / application.properties 去掉"改成 never"的误导建议:schema.sql 幂等,always 是安全默认;改 never 会让后续新增表在本地缺失(曾踩坑) - README 加建表两路径说明 + 缺表/缺列排查(down -v 重建卷) 验证:一次性 throwaway 容器跑 init.sql→schema.sql 两遍 exit=0、无缺列崩溃、 user_identities 建成且幂等。全量 252 测试通过。
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes InvolutionHell/involutionhell#297
漏洞
/openai/responses/stream烧付费 LLM 额度,但只有@SaCheckLogin没有任何限流:登录用户可绕过 Next.js 层的 Upstash 限流直接 curl 后端刷额度(Caddy 裸 reverse_proxy 透传不过滤路径)。#297 里已确认当前线上 key 是过期的 Intern-S1 key、暂不失血,但换真 key 的那天洞就复活——限流必须落在 Java 层本身。修复
OpenAiStreamRateLimiter:Caffeine(已有依赖)每用户固定窗口计数,默认 10 次/分钟(OPENAI_STREAM_RPMenv 可调),超限抛 429。进程内存级即可——后端单实例部署;将来横向扩容换 Redis 计数,接口不变。窗口边界突发(瞬时最多 2N)对防刷额度场景无关紧要,不为此上滑动窗口rateLimiter.checkOrThrow(StpUtil.getLoginIdAsLong())验证
./mvnw test全量 246 个测试通过(含 SecurityInvariantsTests 全部既有不变量)@Autowired🤖 Generated with Claude Code
https://claude.ai/code/session_01USN2Liwrjd9TKVFJo5Za51