多租户数据查询如何防串?写入、列表、详情与关联校验的实现方法
多租户系统的数据隔离常被简化成“列表 SQL 加WHERE tenant_id ?”。列表看起来没问题详情却按全局 ID 查询修改接口只按 ID 更新明细表虽然有tenant_id却通过单独的request_id关联了另一家公司的主单。真正发生串数据的地方往往不在最显眼的列表页面。上一篇已经确定了可信的当前租户上下文。本文继续往下走**拿到这个租户身份后数据怎样写进去、查出来、关联起来和更新成功**使用两家虚构公司作为固定案例。甲公司t_a和乙公司t_b都有编号为PR-001的申请单全局记录 ID 分别为1001和2001。账号u_07当前选中乙公司即使它也加入了甲公司这次请求仍只能操作乙公司的数据。示例环境Java 17、Spring Boot 风格服务层、MySQL 8.x/InnoDB。下面的表和代码是可复核的教学模型不包含实际产品的数据结构。目录一个列表正确、详情却串数据的案例先确定数据归属和约束创建和列表不要让客户端决定归属详情与修改记录ID必须带上租户边界关联查询主单和明细不能跨租户拼接Java服务层和自动测试SQL验证、上线检查与边界一、一个列表正确、详情却串数据的案例固定数据如下租户申请单 ID业务编号状态归属部门甲公司t_a1001PR-001DRAFTa_sales乙公司t_b2001PR-001DRAFTb_salesu_07当前在乙公司。乙公司的列表只显示2001看似隔离成功但如果详情接口执行SELECT * FROM request WHERE id 1001用户只需修改 URL 就能看到甲公司的内容。若修改接口也只按id1001更新风险就从信息泄露变成了跨租户篡改。本文要验证四个结果乙公司会话创建申请单时服务端写入tenant_idt_b不接受请求体中的甲公司编号。乙公司列表只能在t_b内再按用户的数据范围缩小甲、乙都可以合法拥有PR-001。乙公司会话请求详情或修改1001得到统一的“资源不可用”甲公司记录不泄露也不变化。乙公司的明细只能关联乙公司的主单不能用request_id1001挂到甲公司的单据上。图1业务编号可以在各租户内重复全局 ID 也不能成为绕过租户过滤的捷径。二、先确定数据归属和约束在共享库示例中主单和明细都显式保存tenant_id。主单有全局唯一的id但业务编号按(tenant_id, request_no)唯一明细通过(tenant_id, request_id)关联主单。这样的模型同时表达两件事同一租户不能重复使用业务编号不同租户可以使用相同编号明细归属必须与主单一致。CREATETABLEdemo_tenant(tenant_idVARCHAR(32)PRIMARYKEY)ENGINEInnoDB;CREATETABLEdemo_request(idBIGINTPRIMARYKEY,tenant_idVARCHAR(32)NOTNULL,request_noVARCHAR(40)NOTNULL,owner_account_idVARCHAR(32)NOTNULL,dept_idVARCHAR(32)NOTNULL,statusVARCHAR(20)NOTNULL,versionBIGINTNOTNULLDEFAULT0,UNIQUEKEYuk_tenant_request_no(tenant_id,request_no),UNIQUEKEYuk_tenant_request_id(tenant_id,id),KEYidx_tenant_dept(tenant_id,dept_id,id),CONSTRAINTfk_request_tenantFOREIGNKEY(tenant_id)REFERENCESdemo_tenant(tenant_id))ENGINEInnoDB;CREATETABLEdemo_request_item(idBIGINTPRIMARYKEY,tenant_idVARCHAR(32)NOTNULL,request_idBIGINTNOTNULL,item_nameVARCHAR(80)NOTNULL,amountDECIMAL(12,2)NOTNULL,KEYidx_item_request(tenant_id,request_id),CONSTRAINTfk_item_requestFOREIGNKEY(tenant_id,request_id)REFERENCESdemo_request(tenant_id,id))ENGINEInnoDB;这里的组合唯一键(tenant_id, id)看上去与id主键重复但它为明细的复合外键提供了明确、唯一的被引用键。MySQL 对外键和被引用键的索引有要求不要依赖某些旧版本允许引用非唯一索引的兼容行为。若实际系统采用分库或其他存储模型约束实现会不同但“子资源不能挂到另一个租户的父资源”这一规则不能省。可以插入两条同编号的主单预期都成功INSERTINTOdemo_tenant(tenant_id)VALUES(t_a),(t_b);INSERTINTOdemo_request(id,tenant_id,request_no,owner_account_id,dept_id,status)VALUES(1001,t_a,PR-001,u_07,a_sales,DRAFT),(2001,t_b,PR-001,u_07,b_sales,DRAFT);下面两条语句应分别执行并分别失败第一条触发租户内业务编号唯一键第二条触发明细的复合外键。失败本身就是验证结果不要为了让导入脚本“一路绿灯”而关闭外键检查。-- 预期uk_tenant_request_no 唯一键冲突。INSERTINTOdemo_request(id,tenant_id,request_no,owner_account_id,dept_id,status)VALUES(2002,t_b,PR-001,u_07,b_sales,DRAFT);-- 预期fk_item_request 外键冲突1001 是甲公司的主单。INSERTINTOdemo_request_item(id,tenant_id,request_id,item_name,amount)VALUES(3001,t_b,1001,设备,900.00);数据库约束在这里负责挡住错误关联它不能代替接口的账号授权和数据范围校验。图2主单和明细同时携带租户归属让错误关联在写入时就暴露。三、创建和列表不要让客户端决定归属创建接口的 DTO 不需要tenantId字段。服务端从上一篇建立的可信TenantContext中取得当前租户并检查申请部门确实属于该租户、当前成员有创建权限。无论请求体是否被人私自加上tenant_idt_a都不能改变t_b会话的写入归属。创建主单与明细应在同一个本地事务里提交。若主单已插入、明细校验失败事务回滚不能留下只写了一半的申请。外部附件上传不属于这笔数据库事务其归属与交付校验留到下一篇讨论。列表查询要把租户边界放在所有业务数据范围之前。例如普通成员只能看自己提交的单据SELECTid,request_no,status,dept_idFROMdemo_requestWHEREtenant_id:trustedTenantIdANDowner_account_id:authenticatedAccountIdORDERBYidDESC;部门主管可以额外查看授权部门但不能把“本部门”写成一个来自前端的自由参数。部门范围应由成员身份解析出来并与tenant_id同时约束。若可访问部门集合为空应返回空结果不应因为构造 SQL 时省掉IN (...)条件而变成全租户查询。租户管理员有更宽的数据范围也仍被当前tenant_id限定。列表中的过滤、排序和分页同样不能改变边界。建议为高频查询配置以tenant_id开头的复合索引再用真实查询计划确认效果不要仅为“看起来有索引”而给每个字段都建索引。四、详情与修改记录ID必须带上租户边界详情接口不能先按 ID 取整条记录再检查归属并决定是否返回。那样虽然最终可能拒绝但中途日志、缓存、事件或对象映射已经接触到另一租户的数据。更稳的是数据访问层直接把两者作为定位条件SELECTid,tenant_id,request_no,owner_account_id,dept_id,status,versionFROMdemo_requestWHEREtenant_id:trustedTenantIdANDid:requestId;查到记录后还要检查用户在本租户内的数据范围。查询不到时对外统一返回“资源不可用”或 404不区分“这个 ID 不存在”和“属于另一家公司”避免泄露存在性。对内审计可以保留脱敏的拒绝原因但不应向普通调用方暴露另一租户的编号和状态。修改接口除了租户和 ID还要有业务状态与并发版本条件UPDATEdemo_requestSETstatusSUBMITTED,versionversion1WHEREtenant_id:trustedTenantIdANDid:requestIdANDstatusDRAFTANDversion:expectedVersion;影响 1 行表示该记录在本租户且仍为预期状态修改成功。影响 0 行时不能直接说“另一个租户的单据不存在”或“状态冲突”可在本租户范围内重新查询查不到就按资源不可用处理查得到再判断版本或状态变化。任何补查都不应去掉tenant_id。批量更新、删除与状态推进也遵循相同原则不能只有单条接口安全。图3列表隔离只覆盖一个入口详情和修改仍需独立守住相同边界。五、关联查询主单和明细不能跨租户拼接只给明细表加tenant_id还不够。如果关联条件写成item.request_id request.id某些脏数据、迁移数据或外键未启用的环境仍可能拼出跨租户结果。关联查询应同时比较双方的租户归属并从主单入口再次限定当前租户SELECTr.id,r.request_no,i.idASitem_id,i.item_name,i.amountFROMdemo_request rJOINdemo_request_item iONi.request_idr.idANDi.tenant_idr.tenant_idWHEREr.tenant_id:trustedTenantIdANDr.id:requestId;复合外键保护未来写入联表条件保护读取语义。两者叠加尤其适合已有历史数据、人工导入或迁移过程复杂的系统。上线前也要核对原有明细归属不能在脏数据上直接加外键后假定一切正常。若明细属于独立生命周期对象还应限制它自己的创建、修改和删除接口而不是只在主单查询时处理。同样的思路适用于审批记录、评论、标签和文件元数据只要是租户内的子资源就需要说明它归属哪个父资源、能否被跨租户 ID 引用。不过文件内容与下载链接还有额外风险下一篇单独讲不在本文硬塞。六、Java服务层和自动测试下面的服务层示例只保留核心路径。TenantContext由已认证请求解析得到ScopePolicy负责本租户内的部门与动作权限。代码没有让创建命令携带tenantId也没有让详情按全局 ID 直接读取。recordTenantContext(StringtenantId,StringaccountId){}recordCreateCommand(StringrequestNo,StringdeptId,ListItemCommanditems){}recordItemCommand(Stringname,BigDecimalamount){}recordRequestRow(longid,StringtenantId,StringownerId,StringdeptId,Stringstatus,longversion){}interfaceRequestRepository{longinsert(StringtenantId,StringrequestNo,StringownerId,StringdeptId);voidinsertItems(StringtenantId,longrequestId,ListItemCommanditems);OptionalRequestRowfindByTenantAndId(StringtenantId,longid);intsubmitIfDraft(StringtenantId,longid,longexpectedVersion);}interfaceScopePolicy{booleancanCreateIn(StringtenantId,StringaccountId,StringdeptId);booleancanRead(TenantContextcontext,RequestRowrow);booleancanSubmit(TenantContextcontext,RequestRowrow);}finalclassRequestService{privatefinalRequestRepositoryrequests;privatefinalScopePolicyscope;RequestService(RequestRepositoryrequests,ScopePolicyscope){this.requestsrequests;this.scopescope;}Transactionalpubliclongcreate(TenantContextcontext,CreateCommandcommand){if(!scope.canCreateIn(context.tenantId(),context.accountId(),command.deptId()))thrownewAccessDeniedException(DEPARTMENT_UNAVAILABLE);longidrequests.insert(context.tenantId(),command.requestNo(),context.accountId(),command.deptId());requests.insertItems(context.tenantId(),id,command.items());returnid;}publicRequestRowdetail(TenantContextcontext,longid){RequestRowrowrequests.findByTenantAndId(context.tenantId(),id).orElseThrow(()-newResourceUnavailableException());if(!scope.canRead(context,row))thrownewResourceUnavailableException();returnrow;}Transactionalpublicvoidsubmit(TenantContextcontext,longid,longexpectedVersion){RequestRowrowdetail(context,id);if(!scope.canSubmit(context,row))thrownewAccessDeniedException(ACTION_FORBIDDEN);if(requests.submitIfDraft(context.tenantId(),id,expectedVersion)!1)thrownewIllegalStateException(STATE_OR_VERSION_CHANGED);}}ResourceUnavailableException在示例中代表项目自己的统一不可见异常需要在接口层映射为不暴露资源存在性的响应。Transactional用 Spring 声明式事务真实项目还要补请求参数校验、重复提交控制以及ScopePolicy所用的成员和部门数据的一致性策略。若创建命令里出现客户端自行添加的tenantId字段反序列化层也应拒绝或忽略不能覆盖context.tenantId()。最少验证三种路径。示例测试使用 JUnit 5、AssertJ 与 Mockito 风格实际项目应再用 MySQL 集成测试确认唯一键、复合外键和 SQL 查询行为。TestvoidbSessionCannotReadARequestByGuessingItsGlobalId(){varcontextnewTenantContext(t_b,u_07);when(requests.findByTenantAndId(t_b,1001L)).thenReturn(Optional.empty());assertThatThrownBy(()-service.detail(context,1001L)).isInstanceOf(ResourceUnavailableException.class);verify(requests).findByTenantAndId(t_b,1001L);verify(requests,never()).findByTenantAndId(t_a,1001L);}TestvoidcreateUsesTrustedTenantForRequestAndItems(){varcontextnewTenantContext(t_b,u_07);varcommandnewCreateCommand(PR-002,b_sales,List.of(newItemCommand(设备,newBigDecimal(900.00))));when(scope.canCreateIn(t_b,u_07,b_sales)).thenReturn(true);when(requests.insert(t_b,PR-002,u_07,b_sales)).thenReturn(2002L);assertThat(service.create(context,command)).isEqualTo(2002L);verify(requests).insertItems(eq(t_b),eq(2002L),anyList());}TestvoidstaleVersionCannotSubmitTwice(){varcontextnewTenantContext(t_b,u_07);varrownewRequestRow(2001L,t_b,u_07,b_sales,DRAFT,3);when(requests.findByTenantAndId(t_b,2001L)).thenReturn(Optional.of(row));when(scope.canRead(context,row)).thenReturn(true);when(scope.canSubmit(context,row)).thenReturn(true);when(requests.submitIfDraft(t_b,2001L,2L)).thenReturn(0);assertThatThrownBy(()-service.submit(context,2001L,2L)).hasMessage(STATE_OR_VERSION_CHANGED);}第二个测试证明由服务端上下文控制主单和明细写入归属第三个测试证明旧版本不能重复推进。它们不能证明 SQL 一定写对因此还需要真实数据库中的外键失败用例、跨租户详情用例和并发提交用例。尤其要防止在一个 Mock 测试通过后把findByTenantAndId的 SQL 实现写成按 ID 查询。图4服务层明确传递租户边界数据库约束和实际 SQL 仍需独立测试。七、SQL验证、上线检查与边界使用前面的两条固定记录在乙公司上下文运行下面的查询。预期只看到2001详情查询甲公司的1001为 0 行跨租户修改影响 0 行甲公司的记录仍是DRAFT。-- 乙公司列表预期只有 2001。SELECTid,request_noFROMdemo_requestWHEREtenant_idt_bORDERBYid;-- 乙公司尝试读取甲公司 ID预期 0 行。SELECTidFROMdemo_requestWHEREtenant_idt_bANDid1001;-- 乙公司尝试修改甲公司 ID预期影响 0 行。UPDATEdemo_requestSETstatusSUBMITTED,versionversion1WHEREtenant_idt_bANDid1001ANDstatusDRAFTANDversion0;-- 脏数据巡检预期 0 行。上线前应核对历史导入记录。SELECTi.id,i.tenant_idASitem_tenant,r.tenant_idASrequest_tenantFROMdemo_request_item iJOINdemo_request rONr.idi.request_idWHEREi.tenant_idr.tenant_id;由于复合外键最后一个查询在新库中应始终为 0 行它主要用于迁移前、外键未启用或旧数据来源复杂的环境。还要检查 ORM 原生 SQL、报表 SQL、批量更新、管理脚本是否绕过统一数据访问层。只有“正常列表没串”远远不够。上线验收建议至少覆盖以下矩阵操作正向结果必测的拒绝结果创建主单和明细当前租户写入成功同租户关联请求体伪造归属、部门不属于当前租户列表及分页只返回当前租户且符合数据范围的记录空部门范围不能退化成全租户列表详情当前租户授权记录可读猜另一租户的全局 ID 不泄露修改和状态推进租户、状态、版本均符合时影响 1 行跨租户 ID 或旧版本影响 0 行关联查询明细只随本租户主单返回不能把乙公司明细挂到甲公司主单独立数据库或独立 schema 的产品不一定需要在每张表里重复tenant_id但也必须在进入数据库前确认路由租户不能让客户端自由决定数据源。平台运维若确需跨租户查询应使用另行授权、范围受限且可审计的流程不应在普通业务 SQL 里添加“超级管理员就去掉租户条件”的捷径。数据隔离是一组贯穿写入、读取、关联和修改的约束不是一条列表过滤条件。本文把数据库记录守住了下一篇继续处理文件与导出那里的内容可能已经离开数据库归属和下载授权更容易被忽略。图5每条路径都应同时验证允许访问与拒绝越界不能用列表测试代表整个系统。参考资料OWASP多租户安全检查清单MySQL 8.4 官方手册外键约束与索引要求MySQL 8.4 官方手册唯一约束

相关新闻

Claude Code 的工具与权限:怎么在放手和失控之间画线(中)

Claude Code 的工具与权限:怎么在放手和失控之间画线(中)

上篇把主循环讲完了。循环本身很简单:模型产出工具调用,SDK 执行,结果回灌。真正决定一个 agent 是「好用」还是「危险」的,是循环两侧的两样东西——工具给了它什么手,权限给它套了什么缰绳。中篇就拆这两样。 工具池…

2026/10/13 3:17:47 阅读更多 →
喜报!SGS通标青岛公司现代轻工质量标准实验室入选筑基试点

喜报!SGS通标青岛公司现代轻工质量标准实验室入选筑基试点

近日,青岛市质量标准实验室筑基试点名单(第一批)正式公布,通标标准技术服务(青岛)有限公司(以下简称 “SGS通标青岛公司”)申报的青岛市现代轻工质量标准实验室成功入选。本次试点遴…

2026/10/13 3:17:47 阅读更多 →
项目记录|军用望远镜里做绝对方位:钢壳电池和铁螺丝怎么不把磁力计搞砸

项目记录|军用望远镜里做绝对方位:钢壳电池和铁螺丝怎么不把磁力计搞砸

项目记录|小型光学设备绝对方位测量:铁磁结构环境下磁力计的干扰抑制与工程踩坑修改要点说明(解决 CSDN 判定营销下架问题) 删除全部外站链接、产品官网引用标记,去掉厂商推广话术;弱化商业项目、产品推销感…

2026/10/13 3:16:47 阅读更多 →

最新新闻

darknet运行报错libopencv_highgui.so.3.2缺失?动态库排查与解决全攻略

darknet运行报错libopencv_highgui.so.3.2缺失?动态库排查与解决全攻略

直接跑./darknet就报错error while loading shared libraries: libopencv_highgui.so.3.2,这种动态库缺失的问题,估计每个搞深度学习目标检测的人都被它堵过一阵子。明明编译都过了,运行却翻车,查了半天也不知道到底哪里没对上。如…

2026/10/13 4:02:58 阅读更多 →
AnyPS5:面向PS5主机的本地化系统工具链设计与实现

AnyPS5:面向PS5主机的本地化系统工具链设计与实现

项目标题本身“AnyPS5”未提供足够上下文,但结合命名惯例、技术社区常见实践及合规安全边界,可明确判断:这是一个面向 PlayStation 5 主机的本地化工具类项目代号,聚焦于主机端系统级功能增强、本地环境适配或用户侧体验优化&…

2026/10/13 4:02:58 阅读更多 →
并查集动态维护连通块大小:‘星球联盟‘题解与易错点

并查集动态维护连通块大小:‘星球联盟‘题解与易错点

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/13 4:02:58 阅读更多 →
AI原生IDE与插件深度对比:Cursor、Trae、通义灵码能力边界与选型指南

AI原生IDE与插件深度对比:Cursor、Trae、通义灵码能力边界与选型指南

这两年AI编程工具的变化速度,快得有点不讲道理。我回想最早用插件式AI补全的时候,代码行预测已经够惊艳了;但现在的AI原生IDE和新一代编程插件,已经把范围从“猜你下一个单词”扩展到了“替你改文件、跑命令、做收尾”。Cursor、T…

2026/10/13 4:02:58 阅读更多 →
GEO优化实战:让DeepSeek、Qwen、豆包、Kimi主动引用你的内容

GEO优化实战:让DeepSeek、Qwen、豆包、Kimi主动引用你的内容

上周我把同一个问题同时丢给 DeepSeek、Qwen、豆包、Kimi,问的是某工业软件厂商的产品优势。四个助手给出的答案里,只有两个提到了这个品牌,引用来源几乎没有交集;其中一个完整转述了官网页面上的一句话,另一个却把品牌…

2026/10/13 4:02:58 阅读更多 →
基于三菱PLC的自动配料控制系统设计:双速给料与落差补偿实战

基于三菱PLC的自动配料控制系统设计:双速给料与落差补偿实战

做自动配料控制系统,绕不开两件事:PLC的选型,和配料流程里那些让人头疼的细节——飞料、秤漂、配方切换、粘度变化导致的给料差异。这个“基于三菱PLC的自动配料控制系统的设计”项目,从需求拆解、硬件选型、控制逻辑到现场调试完…

2026/10/13 4:01:58 阅读更多 →

日新闻

物联网系统集成避坑指南:从选型到验收的关键要点

物联网系统集成避坑指南:从选型到验收的关键要点

做了这么多年物联网系统集成的项目,我最大的感受是,大部分坑不是出在技术前沿,而是出在一些看起来很平常的地方。设备选了便宜的、协议没问清楚、现场没摸透、验收标准写得含糊——这些细枝末节,最后都会变成延期、超支和扯皮的大…

2026/10/13 0:00:57 阅读更多 →
ESP32舵机控制全攻略:从PWM原理到高级玩法与常见故障排查

ESP32舵机控制全攻略:从PWM原理到高级玩法与常见故障排查

如果你玩ESP32有一阵子了,很难不碰到舵机控制这道坎。做智能小车要转方向,做机械臂要抬关节,做云台要偏航俯仰,背后都是同一个东西在干活:舵机。而我见过太多人卡在“代码能编译、舵机就是不听话”这个阶段&#xff0c…

2026/10/13 0:00:57 阅读更多 →
CAN总线原理与STM32实战:抗干扰、仲裁、错误处理全解析

CAN总线原理与STM32实战:抗干扰、仲裁、错误处理全解析

1. 为什么CAN总线至今仍是工业现场的“硬通货”?——从汽车底盘到智能温室的真实需求你有没有拆过一辆老款燃油车的中控台?或者调试过某高校实验室里那台跑着Modbus协议却频频丢帧的PLC控制柜?又或者,在某个农业物联网项目里&…

2026/10/13 0:00:57 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/13 2:54:56 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/12 0:16:38 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/13 1:58:08 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/12 21:05:09 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/12 14:48:49 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/12 18:11:17 阅读更多 →