节点在线、应用在线、配置在线使用令牌查询
|
# 项目隔离与æƒé™æ”¹è¿›æ–¹æ¡ˆï¼ˆæœ€å°æ”¹åŠ¨ç‰ˆï¼‰
> 制定日期:2026-07-24
> 便®ï¼š`Doc/架构审查与æƒé™åˆ†æž.md` çš„æƒé™ä¸“题结论
> ç›®æ ‡ï¼šå®žçŽ°é¡¹ç›®çº§æ•°æ®éš”ç¦»ï¼ˆå µä½è·¨é¡¹ç›®æ³„éœ²ï¼‰ï¼ŒåŒæ—¶æ»¡è¶³çº¦æŸâ€”—**æœ€å°æ”¹åŠ¨ã€æœ€ç®€æ”¹æ³•ã€å¤ç”¨ä¼˜å…ˆã€é«˜å†…èšä½Žè€¦åˆã€éžå¿…è¦ä¸åŠ ProjectId 列**。
---
## 0. 设计约æŸï¼ˆç”¨æˆ·æ˜Žç¡®è¦æ±‚)
1. **éžå¿…è¦ä¸åœ¨è¡¨ä¸åŠ `ProjectId` 列**:é¿å… 49 å¼ è¡¨çš„ schema è¿ç§»ä¸Žæ•°æ®å›žå¡«é£Žé™©ã€‚
2. **所有必须跟项目挂钩的 CRUD 都è¦å¢žåŠ é¡¹ç›®è¿‡æ»¤**:读(列表/详情)+ 写(新增/修改/åˆ é™¤ï¼‰ä¸€å¾‹æ ¡éªŒé¡¹ç›®ä½œç”¨åŸŸã€‚
3. **æœ€å°æ”¹åЍ**:ä¸é‡å†™æ¯ä¸ªæŸ¥è¯¢ï¼›é€»è¾‘集ä¸ã€å„接入点å•行改动。
4. **高内èšä½Žè€¦åˆ**:过滤逻辑å•一èŒè´£ã€å¯å•测ã€ä¸Žä¸šåŠ¡æŽ§åˆ¶å™¨è§£è€¦ã€‚
---
## 1. æ ¸å¿ƒæ€è·¯ï¼šèšåˆæ ¹é—´æŽ¥éš”离
- èšåˆæ ¹ `App` / `Node` **已带 `ProjectId`**(数æ®å·²å˜åœ¨ï¼Œæ— éœ€åŠ åˆ—ï¼‰ã€‚
- ç»å¤§å¤šæ•°æ˜Žç»†/æ—¶åºè¡¨é€šè¿‡ `AppId` 或 `NodeId` å…³è”到èšåˆæ ¹ → 用 `父级.ProjectId` 间接过滤,**零新增列**。
- 过滤逻辑集ä¸åˆ°ä¸€ä¸ªå¯å¤ç”¨ç»„ä»¶ï¼›å„æŽ§åˆ¶å™¨åªæ”¹åŸºç±»ç»§æ‰¿ï¼ˆä¸€è¡Œï¼‰æˆ–调一个扩展方法。
```
明细表(AppId/NodeId) → App/Node(ProjectId) → 用户å…许的项目集åˆ
```
---
## 2. 架构设计(三个新增ã€èŒè´£å•一)
### 2.1 `ProjectScopeService`(解æž"当å‰ç”¨æˆ·èƒ½çœ‹å“ªäº›é¡¹ç›®")
- 输入:当å‰ç™»å½•用户(Cube `ManageProvider.User`)。
- 输出:`IList<Int32> AllowedProjectIds` + `Int32? SelectedProjectId`。
- 规则:
- 超级管ç†å‘˜ï¼ˆç‰¹å®šè§’色)→ å…许全部项目(哨兵值)。
- 普通用户 → æ¥è‡ª `ProjectUser`(用户-项目绑定表,**当å‰ä»Žæœªè¢«æŸ¥è¯¢ä½¿ç”¨ï¼Œæœ¬æ¬¡æ£å¼å¯ç”¨**)。
- `SelectedProjectId` å–自 URL `projectId`ï¼›**å¿…é¡»è½åœ¨ Allowed 内**,å¦åˆ™å¿½ç•¥ï¼ˆé˜²è¶Šæƒï¼šä½Žæƒç”¨æˆ·æ‰‹å¡«ä»–人项目 ID)。
- æ¯è¯·æ±‚è§£æžä¸€æ¬¡ï¼Œç¼“å˜åˆ° `HttpContext.Items`,é¿å…é‡å¤æŸ¥åº“。
### 2.2 `ProjectFilter`(纯函数/扩展,å¯å•æµ‹ï¼Œä¸Žæ¡†æž¶æ— å…³ï¼‰
- `BuildOql<TEntity>(ProjectScope scope)` 返回 XCode `OQL` / `WhereExpression`:
- T 直接有 `ProjectId` → `ProjectId In(allowed)`;若 selected éžç©ºåˆ™ `ProjectId == selected`。
- T 有 `AppId` → `AppId In(allowedAppIds)`ï¼Œå…¶ä¸ `allowedAppIds = App.FindByProject(allowed).IDs`(按请求缓å˜ï¼‰ã€‚
- T 有 `NodeId` → `NodeId In(allowedNodeIds)`,åŒç†ã€‚
- T ä¸¤è€…çš†æ— â†’ 返回 `null`(全局表,ä¸å¼ºåˆ¶ï¼›debug 下æ–言æé†’,待人工确认是å¦çœŸå…¨å±€ï¼‰ã€‚
- 写æ“作å¤ç”¨åŒä¸€è§£æžï¼š`ResolveProjectId(TEntity e)` 通过父级 App/Node åæŸ¥ ProjectIdï¼Œä¾›æ ¡éªŒã€‚
### 2.3 `ProjectScopedController<TEntity>`ï¼ˆåŸºç±»ï¼Œæœ€å°æŽ¥å…¥ï¼‰
- 继承 Cube `EntityController<TEntity>`,**集ä¸é‡å†™**读/写钩å:
- `Search(Pager p)`ï¼šå– Cube 原生 where → `where &= ProjectFilter.BuildOql<T>(scope)` → æ£å¸¸åˆ†é¡µã€‚
- `Add/Update/Delete` å‰ç½®æ ¡éªŒï¼šè°ƒ `ProjectFilter.ResolveProjectId(entity)` æ–言属于 Allowedï¼›å¦åˆ™æ‹’ç»ï¼ˆé˜²è¶Šæƒå†™ï¼‰ã€‚
- 接入方å¼ï¼šä½œç”¨åŸŸå†…的控制器把 `: EntityController<X>` 改为 `: ProjectScopedController<X>`(**æ¯æ–‡ä»¶ä¸€è¡Œ**)。
- éžä½œç”¨åŸŸï¼ˆçœŸæ£å…¨å±€ï¼‰çš„æŽ§åˆ¶å™¨ä¸åŠ¨ã€‚
> é‡å†™ç‚¹ç¡®è®¤ï¼šå®žæ–½å‰ç”¨ DeepWiki 查 `NewLifeX/X`(NewLife.Cube)的 `EntityController.Search` 确切ç¾å,确ä¿é‡å†™å…¼å®¹ï¼›è‹¥ Cube ä¸ç›´æŽ¥æš´éœ² where,则改为在 `FindAll` 外包一层 `Search` æ‰©å±•æ–¹æ³•ï¼ˆåŒæ ·æ˜¯é›†ä¸é€»è¾‘ + å•行调用)。
---
## 3. 实体分类与过滤方å¼ï¼ˆé›¶åŠ åˆ—ï¼‰
| 类别 | 代表表 | è¿‡æ»¤æ–¹å¼ |
|------|--------|----------|
| 直接 ProjectId(已å˜åœ¨ï¼‰ | Appã€Nodeã€AppDeployã€AppConfigã€AppTracerã€AlarmGroupã€GatewayCluster/Routeã€MySqlNodeã€RedisNode | 直接 `ProjectId In(allowed)` |
| ç» AppId | AppServiceã€AppConsumeã€AppMeterã€AppHistoryã€AppCommandã€AppClientLogï¼›TraceDataã€SampleDataã€Trace*/App*Stat(appId);AppDeployNode/Version/Historyï¼ˆç» AppDeploy→App) | `AppId In(allowedAppIds)` |
| ç» NodeId | NodeDataã€NodeCommandã€NodeHistoryã€NodeStatã€NodeVersionã€NodeRuleã€NodeLocationï¼›RedisData/MySqlDataï¼ˆç» RedisNode/MySqlNode) | `NodeId In(allowedNodeIds)` |
| 全局(待评审确认) | Attachmentã€SslCertificateã€McpAuditã€RedisMessageQueue ç‰ | 默认ä¸å¼ºåˆ¶ï¼›é€è¡¨ç¡®è®¤çˆ¶é“¾ï¼Œèƒ½æŒ‚çˆ¶çº§åˆ™æŒ‰çˆ¶çº§è¿‡æ»¤ï¼Œç¡®å±žç³»ç»Ÿçº§å†æ ‡æ³¨å…¨å±€å¹¶è¯„审 |
> 实施时é€è¡¨ç¡®è®¤ `AppId/NodeId` 父链(数æ®é©±åŠ¨ï¼‰ï¼Œä¸è‡†æµ‹ï¼›å¯¹æ‹¿ä¸å‡†çš„表**ä¿å®ˆå¤„ç†**ï¼ˆæŒ‚çˆ¶é“¾è¿‡æ»¤æˆ–æ˜¾å¼æ ‡æ³¨+评审),é¿å…æ¼è¿‡æ»¤ã€‚
---
## 4. 实施æ¥éª¤ï¼ˆæœ€å°æ”¹åŠ¨é¡ºåºï¼‰
1. **新增 `ProjectScopeService`**ï¼šè§£æž Allowed/Selected,å¯ç”¨ `ProjectUser`,定义超级管ç†å‘˜åˆ¤å®šï¼Œè¯·æ±‚级缓å˜ã€‚
2. **新增 `ProjectFilter`**:`BuildOql<T>` + `ResolveProjectId`,纯函数ã€å•测覆盖。
3. **新增 `ProjectScopedController<T>`** 基类:é‡å†™ Search/Add/Update/Delete 注入作用域(先确认 Cube é‡å†™ç‚¹ï¼‰ã€‚
4. **接入控制器**:把作用域内的约 30 个控制器改为继承基类(æ¯å¤„一行)。全局表控制器ä¸åŠ¨ã€‚
5. **Server ä¾§ API 审计(次è¦ï¼‰**:`Stardust.Server` ä¸æŽ¥å— `appId/nodeId` 的接å£ï¼Œæ ¡éªŒè°ƒç”¨æ–¹èº«ä»½æ‰€å±žé¡¹ç›®ï¼Œé˜²æ¢è·¨é¡¹ç›®è¯»å–(客户端/ä»£ç†æœ¬å°±å‡ App/Node å‡è¯è°ƒç”¨ï¼Œé£Žé™©ä½Žï¼ŒæŒ‰éœ€è¡¥ï¼‰ã€‚
6. **Vue å‰å°ï¼ˆå¯é€‰ï¼‰**:æœåŠ¡ç«¯å·²æŒ‰ç”¨æˆ·å¼ºåˆ¶ä½œç”¨åŸŸï¼ŒVue æ— éœ€æ”¹è¿‡æ»¤é€»è¾‘ï¼›ä»…å¯é€‰åŠ "当å‰é¡¹ç›®"选择器æå‡ä½“验,列表请求带 `projectId` 仅作便æ·ã€‚
---
## 5. 验è¯
- **啿µ‹ï¼ˆå…³é”®ï¼‰**ï¼šæž„é€ ä»…å±ž Project A 的普通用户,调用 `AppService` / `TraceData` / `ConfigData` / `AppDeployNode` ç‰åˆ—表 API,æ–言**ä»…å« A æ•°æ®**;手填他人 `projectId` 被拒ç»ã€‚
- **回归**:超级管ç†å‘˜ä»å¯è§å…¨éƒ¨ï¼›åˆ†é¡µ/排åº/统计ä¸å—å½±å“。
- å¤ç”¨/新增 `Stardust.ServerTests` 或 Web é›†æˆæµ‹è¯•覆盖上述场景。
---
## 6. 风险与æƒè¡¡
- **性能**:`AppId/NodeId In(åæŸ¥è¯¢)` 作用于å°ä¸”索引良好的 App/Node 表,列表分页影å“å¯å¿½ç•¥ï¼›å¿…è¦æ—¶æŠŠ `allowedAppIds/NodeIds` 物化到请求级缓å˜ã€‚
- **é›¶è¿ç§»**:ä¸åŠ åˆ— → æ— DB è¿ç§»ã€æ— åŽ†å²æ•°æ®å›žå¡«ï¼Œéƒ¨ç½²é£Žé™©æœ€ä½Žï¼ˆç¬¦åˆ"éžå¿…è¦ä¸åŠ åˆ—")。
- **全局表误判**:é é€è¡¨ç¡®è®¤ + ä¿å®ˆé»˜è®¤è§„é¿ï¼›è¯„审清å•留痕。
- **耦åˆåº¦**:过滤逻辑全部在 `ProjectFilter`,控制器零业务侵入;`ProjectScopeService` ä»…ä¾èµ– `ProjectUser` 与 Cube 用户上下文,å¯ç‹¬ç«‹å•测。
---
## 7. 结论
以**「èšåˆæ ¹é—´æŽ¥éš”离 + 集ä¸ä½œç”¨åŸŸåŸºç±»ã€**实现项目级数æ®éš”离:
- 零新增列ã€é›¶ DB è¿ç§»ï¼›
- 控制器å•行接入,逻辑全å¤ç”¨ã€ä¸Žä¸šåŠ¡è§£è€¦ï¼›
- 读/å†™å…¨é“¾è·¯é¡¹ç›®æ ¡éªŒï¼Œå µä½è·¨é¡¹ç›®æ³„露;
- ä¸¥æ ¼å¥‘åˆç”¨æˆ·"æœ€å°æ”¹åŠ¨ã€æœ€ç®€æ”¹æ³•ã€é«˜å†…èšä½Žè€¦åˆã€éžå¿…è¦ä¸åŠ ProjectId"的约æŸã€‚
> 本方案为计划文档,未改动任何æºç ,也未æäº¤ git;待确认åŽè¿›å…¥å®žæ–½ã€‚
|