lovife
|
d05cec0a02
|
feat(tenant): 租户域名 —— 用子域前缀判断"这是哪个单位的站点"(t1.xxx.com / t2.xxx.com)
客户新提:不同的租户采用不同的地址前缀来获取租户ID。
一、它解决什么
在此之前"这次是哪个单位"都要人填或扫:PC 登录要手填租户码(跨单位重名时报 40012
「请填写租户码」,而用户根本不知道该填什么)、H5 与小程序靠扫码 scene。
而域名本身就是"我是谁"最自然的答案 —— 在 t1.xxx.com 上打开页面时,
系统不该再问"你是哪个单位的"。
前缀用 t{tenantId},与扫码 scene 的 t{tid} **同一套约定**(scene 早就是 t1-k17),
不引入第二套编号。
二、★ 唯一必须守住的规则:Host 定位,token 授权
未登录 → Host 决定"去哪个单位里找这个人"
已登录 → 一律以 token 里的 tenantId 为准,且 Host 不一致就拒绝
不校验后者的话:在 t1.xxx.com 上拿 t2 的 token 就能读 t2 的数据 ——
而界面一切正常(前端本来就会带 token),是个安静且极难发现的越权。
所以 AuthInterceptor 里那段判断比"登录免填租户码"重要得多,E2E 专门守着它。
三、落地
FillProperties.TenantDomain(enabled/base/scheme) 默认关,siteOf(tid) 拼站点地址
support/TenantDomainResolver 解析不出来返回 null(不是错误)
TenantMapper.selectActiveById 停用/已删的租户不解析
UserMapper.selectByTenantIdAndUsername 域名路径按 id 找用户
AuthService.locateUser 域名优先;手填租户码与域名矛盾 → 明确报错
AuthInterceptor Host 与 token 租户不一致 → 403
MpH5AuthController.redirectToApp 按 scene 的 t{tid} 跳回该单位站点
application-dev.yml enabled/base=localhost/scheme=http
null 的语义很重要:解析不出来 ≠ 出错,而是"这是统一入口/单域名部署",回退老路径。
所以单域名部署仍然完全合法(enabled=false 即可)。
四、两条来自微信的硬约束(决定架构,不是可选)
1. 公众号网页授权的「授权回调页面域名」**只能配一个** → 每租户一个子域时,
回调统一落在主域名,再按 scene 里的 t{tid} 302 回该单位站点。
正好复用既有的 state(scene 随 state 走)+ token 放 fragment 的机制。
2. 小程序的 request 合法域名是**固定白名单**,配不了 *.xxx.com →
小程序端用不了域名,继续靠 scene 里的 t{tid}。这点客户需要知道。
五、本地开发的坑(已处理)
开发期 base 是 localhost,真按它回跳会把手机上的学生从穿透域名扔到 t1.localhost ——
打不开,且是浏览器级失败,看不出是我们跳错了。所以回跳加了本机地址判断
(localhost/127.0.0.1/192.168.*/10.*/*.local),本机 base 一律回退到 h5-base-url。
六、E2E:scripts/e2e-m1-tenant-domain.py → 16/16
[1] t1.localhost + 不填租户码 → 登录成功(对照:不带域名 → 40012);
带端口/大小写/多一层子域都能解析
[2] 域名与手填租户码矛盾 → 明确报错;一致则正常
[3] ★ 拿 t1 的 token 访问 t14 域名 → 403,提示可理解
[4] 边界:x1.localhost / t999999.localhost / example.com → 都回退老路径
用 http.client 伪造 Host 头(urllib 会按 URL 自己算 Host,覆盖不掉)。
七、全量 676 条断言、0 失败(新增 16);verify-docs 19 项通过
八、⏳ 需要拍板的三件事(已写进交接摘要 §一·二十五)
1. 正式域名(base)+ 泛域名解析 + 泛域名证书 *.xxx.com(备案一个主域名即可覆盖子域)
2. 要不要保留"手填租户码"(我保留了:统一入口、老客户端、运维排查都需要)
3. 小程序端确认继续靠 scene
另:这条新需求应补进 PRD 与 03-接口设计(目前只落在代码与本摘要里)——下一轮补。
|
2026-09-29 21:37:11 +08:00 |
|