Skip to content

feat(auth): add refresh token module - #229

Open
luoqiz wants to merge 1 commit into
continew-org:devfrom
luoqiz:feat-refresh-token
Open

luoqiz wants to merge 1 commit into
continew-org:devfrom
luoqiz:feat-refresh-token

Conversation

@luoqiz

@luoqiz luoqiz commented Sep 8, 2026

Copy link
Copy Markdown
Contributor

变更类型

  • 新特性(feat)
  • 问题修复(fix)
  • 功能优化(refactor / perf / chore / style)
  • 文档变更(docs)
  • 构建、CI 或依赖升级(build / ci)
  • 测试(test)
  • 其他

破坏性变更

  • 本 PR 包含破坏性变更(BREAKING CHANGE),已在变更目的中说明影响与迁移方式

变更目的

为管理端 Web、App 与小程序提供可轮换的 Refresh Token 登录态,缩短 Access Token 生命周期,并支持安全地恢复过期 Access Token 对应的登录会话。

暂无关联 Issue。

解决方案

  • 新增独立 continew-auth-refresh 模块,集中管理 Refresh Token 签发、轮换、重放保护、会话查询与失效。
  • Web 端通过 HttpOnly Cookie 传输 Refresh Token;App / 小程序通过请求体传输;客户端可配置 Refresh Token 生命周期与传输模式。
  • 增加 Access Session 校验、会话/IP 限流、短暂幂等重放窗口、Cookie 来源白名单和子域通配符限制。
  • 适配登录、刷新、登出、在线用户、强制下线、租户/客户端策略及 WebSocket 会话撤销通知。
  • 保持 AK/SK 第三方访问路径不参与 Refresh Token 处理。

测试情况

  • Refresh Token 认证模块单元测试通过。
  • 已执行 mvn -pl continew-auth-refresh,continew-system,continew-plugin/continew-plugin-tenant,continew-server -am test;格式、编译及认证模块测试通过。
  • 服务端 Spring 上下文测试依赖本机 MySQL/Redis;本地数据库不可用时会出现连接被拒绝,建议由 CI 环境完成最终上下文验证。

Changelog

模块 Changelog Related issues
auth-refresh / system / server / tenant 新增 Refresh Token 轮换、会话管理与多端认证协议适配 暂无关联 Issue

提交前确认

  • 一个 PR 聚焦于 Refresh Token 功能,不夹带无关改动
  • 本地 ./mvnw verify 四道门禁全部通过(完整上下文验证依赖本机 MySQL/Redis)
  • 已完整填写 Changelog,并关联相关 Issue(暂无关联 Issue)
  • commit message 符合 Conventional Commits(约定式提交)规范
  • 如包含 AI 生成的较大改动,相关 commit 已添加 Assisted-by: <智能体> 标记
  • 已签署 CLA(首次贡献可在 PR 创建后按机器人提示完成签署)
  • 目标分支正确:dev(新功能与优化)或 x.x.x 维护分支(仅 Bug 修复)

评审修复

  • 修复 UserServiceImpl.updatePassword(String, String, Long) 的用户策略锁参数解析,解析器现在遍历全部参数,并补充了该签名的单元测试。
  • 移除 ACCESS:* Redis 索引:Access Token 的签名 sid 与 Refresh Session 记录共同完成会话校验,减少每个已认证请求一次 Redis 往返。
  • Refresh IP 限流默认使用连接对端地址;仅在显式配置可信代理地址与跳数后才解析 X-Forwarded-For。会话限流窗口独立配置。
  • 登录审计恢复操作人识别,同时不持久化登录请求体;匿名 logout 不再记录 -1 操作人。
  • 生产环境显式要求 ACCESS_TOKEN_JWT_SECRETREFRESH_TOKEN_SECRET,并拒绝开发默认密钥。

破坏性变更与迁移

  • 登录响应使用 accessToken,客户端不得再读取旧 token 字段。
  • 在线用户强退改以 sessionId 为目标;登出/刷新统一由 /auth/logout/auth/refresh 提供。
  • 新 Access Token 必须包含认证会话 sid;部署升级后,旧会话将被拒绝并要求重新登录。
  • App / 小程序需使用 BODY 模式提交 Refresh Token;Web 端由 HttpOnly Cookie 自动携带。

发布协调与部署

必须与 continew-admin-ui#89 同时合并并同步发布。生产部署需配置两个认证密钥;若经反向代理传递真实客户端地址,需显式配置可信代理地址和跳数。

反向代理与真实客户端 IP(影响限流正确性)

刷新接口的限流默认使用 TCP 连接对端地址,不信任任何 X-Forwarded-For

  • auth.refresh-token.trusted-proxy-hops 默认 0trusted-proxy-addresses 默认为空 → 后端完全不解析 XFF,天然免疫伪造。
  • 后端直接对外(无反向代理):无需任何配置。
  • 经 Nginx / 网关部署时必须显式配置,否则所有用户会共享代理这一个 IP 的限流桶(ip-rate-limit 默认 60 次/分钟将变成全站共享),必然大面积误伤:
auth:
  refresh-token:
    # 填「后端看到的 TCP 对端地址」,即反向代理自身在容器网络中的 IP
    # 注意:不是 upstream 里写的 172.17.0.1,那是代理访问宿主机用的网关地址
    trusted-proxy-addresses: ["<反向代理容器 IP>"]
    # 有几层可信代理就填几层,多层网关时按实际跳数填
    trusted-proxy-hops: 1

白名单取值可在后端容器内查看实际来源地址(docker network inspect <网络名>),或临时打印 request.getRemoteAddr() 确认。

本 PR 同时把 docker/nginx/conf/nginx.conf 的 XFF 由 $proxy_add_x_forwarded_for(追加)改为 $remote_addr(覆盖),即在入口丢弃客户端自带的 XFF 头。原因:后端按「从右往左数 hops 个条目」解析,若 hops 配置错误——

nginx XFF 写法 hops 正确 hops 误配(多填)
$proxy_add_x_forwarded_for(追加) 取到真实 IP 伪造 IP 落在左侧被选中,限流可被绕过
$remote_addr(覆盖,本 PR 后) 取到真实 IP 回退代理 IP,限流退化为共桶——误伤但不产生安全漏洞

即覆盖语义下配置错误是 fail-safe 的,追加语义则会变成可绕过的防护缺口。

@luoqiz
luoqiz force-pushed the feat-refresh-token branch 2 times, most recently from 949bbb4 to 3763ec7 Compare September 9, 2026 05:41
Comment thread pom.xml
@luoqiz
luoqiz force-pushed the feat-refresh-token branch from 8e3adc1 to a40fe6a Compare September 9, 2026 23:10
@Charles7c

Copy link
Copy Markdown
Member

/continew-code-review

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.

2 participants