# 路线 05:从登录追踪到租户隔离、权限检查与后台复验 ## 学习场景 客户登录后查询自己的工单;同一身份提交 Agent 任务,工作进程在稍后执行时重新检查会话和权限;平台员工通过独立入口访问平台功能。沿三个场景观察凭据如何建立、身份如何验证、资源范围如何限制。 图中的后端路径均相对 `src/zhifu/`。连续箭头表示直接函数调用;标注“框架调用”的箭头表示 FastAPI 或 LangGraph 调用已注册函数。间断箭头表示 HTTP、持久数据或框架注册连接,箭头说明具体含义。数据节点使用类名,函数节点使用源码中的函数名。返回[路线目录](README.md)。 ## 图 1:登录与一次工单查询 登录成功产生有效期为 3600 秒的 opaque Bearer token,数据库保存 token 的 SHA-256 摘要。客户查询工单时,服务端重新验证会话、租户与账户状态,然后检查店铺权限及工单客户归属。 ```mermaid flowchart TB CLIENT["客户端
保存登录响应中的 token"] LOGIN["modules/identity/auth.py
login
限流、密码验证与会话创建"] SESSION[("modules/identity/access_models.py
AccessSession
token_hash、有效期与撤销状态")] GET["modules/after_sales/api.py
get_ticket
建立查询事务"] AUTH["modules/identity/auth.py
authenticate
读取 Bearer token 并计算摘要"] HASH["modules/identity/auth.py
authenticate_hash
复查会话、租户和账户"] TENANT[("modules/identity/models.py
Tenant
租户状态")] PRINCIPAL[("modules/identity/access_models.py
Principal
账户归属、类型与状态")] FIND["modules/after_sales/service.py
AfterSalesService.find
按 tenant_id 与资源 id 查询"] ACCESS["modules/after_sales/service.py
AfterSalesService.access
检查客户本人资源"] STORE["modules/identity/auth.py
authorize_store
检查店铺状态与指定权限"] GRANT[("modules/identity/access_models.py
StoreGrant
租户、账户、店铺、permission")] VIEW["modules/after_sales/service.py
AfterSalesService.ticket_view
返回授权范围内工单"] CLIENT -.->|HTTP POST /openapi/v1/auth/sessions;FastAPI 分发| LOGIN LOGIN -.->|事务保存 token 摘要| SESSION LOGIN -.->|HTTP 响应返回 token| CLIENT CLIENT -.->|"HTTP GET /openapi/v1/tickets/{ticket_id};FastAPI 分发"| GET GET --> AUTH AUTH --> HASH SESSION -.->|读取与重新刷新| HASH TENANT -.->|锁定并检查 ACTIVE| HASH PRINCIPAL -.->|锁定并检查 ACTIVE| HASH GET -->|认证成功后| FIND GET -->|取得工单后| ACCESS ACCESS --> STORE GRANT -.->|按四个字段读取权限记录| STORE GET -->|全部检查通过后| VIEW ``` `login` 按账户和客户端地址分别限制每 60 秒 10 次、60 次,失败请求也计数。密码验证通过后,它重新读取账户状态和密码摘要,再登记会话。`authenticate_hash` 对账户记录加锁并重新刷新会话状态,使当前操作与权限撤销具有明确的事务顺序。 `find` 将 `auth.tenant_id` 加入查询;`authorize_store` 检查店铺属于当前租户、处于 `ACTIVE`,且存在指定 `StoreGrant`;`access` 对 `CUSTOMER` 继续检查 `subject_id == actor_id`。无权访问业务资源时返回 `RESOURCE_NOT_FOUND`。身份或会话失效时返回 `UNAUTHENTICATED`。 ### 图 1 源码导航 - [login](G:/leon/miaoa/workspace/shuh-ai/zhifu-platform/src/zhifu/modules/identity/auth.py:104)、[AccessSession](G:/leon/miaoa/workspace/shuh-ai/zhifu-platform/src/zhifu/modules/identity/access_models.py:28):核对 token 返回值与数据库存储字段。 - [get_ticket](G:/leon/miaoa/workspace/shuh-ai/zhifu-platform/src/zhifu/modules/after_sales/api.py:202)、[authenticate](G:/leon/miaoa/workspace/shuh-ai/zhifu-platform/src/zhifu/modules/identity/auth.py:50)、[authenticate_hash](G:/leon/miaoa/workspace/shuh-ai/zhifu-platform/src/zhifu/modules/identity/auth.py:66):追踪请求身份进入 `AuthContext` 的过程。 - [Tenant](G:/leon/miaoa/workspace/shuh-ai/zhifu-platform/src/zhifu/modules/identity/models.py:10)、[Principal](G:/leon/miaoa/workspace/shuh-ai/zhifu-platform/src/zhifu/modules/identity/access_models.py:10)、[StoreGrant](G:/leon/miaoa/workspace/shuh-ai/zhifu-platform/src/zhifu/modules/identity/access_models.py:42):核对租户外键、账户类型和权限作用域。 - [find](G:/leon/miaoa/workspace/shuh-ai/zhifu-platform/src/zhifu/modules/after_sales/service.py:74)、[access](G:/leon/miaoa/workspace/shuh-ai/zhifu-platform/src/zhifu/modules/after_sales/service.py:82)、[authorize_store](G:/leon/miaoa/workspace/shuh-ai/zhifu-platform/src/zhifu/modules/identity/auth.py:90)、[ticket_view](G:/leon/miaoa/workspace/shuh-ai/zhifu-platform/src/zhifu/modules/after_sales/service.py:157)。 - [logout](G:/leon/miaoa/workspace/shuh-ai/zhifu-platform/src/zhifu/modules/identity/auth.py:196):同样调用 `authenticate`,然后将当前 `AccessSession.revoked` 设为 `True`。 ## 图 2:后台 Agent 运行重新验证身份 业务 API 在 `queue_run` 中保存请求身份的 `token_hash`。后台工作进程领取数据库中的任务,再调用编译后的 LangGraph。`build_graph` 注册节点,`graph.ainvoke` 触发节点执行;图中分别标记注册关系和框架调用关系。 ```mermaid flowchart TB API["modules/agent_runtime/api.py
enqueue
认证、店铺授权与幂等检查"] QUEUE["modules/agent_runtime/service.py
queue_run
保存身份与运行配置"] RUN[("modules/agent_runtime/models.py
AgentRun
身份摘要、状态与租约")] WORKER["modules/agent_runtime/worker.py
execute_one
领取并执行一次运行"] CLAIM["modules/agent_runtime/worker.py
claim
领取任务并增加 lease_token"] BUILD["modules/agent_runtime/runtime.py
build_graph
注册节点并 compile"] INVOKE["modules/agent_runtime/worker.py
execute_one.invoke
调用 graph.ainvoke"] LOAD["modules/agent_runtime/runtime.py
build_graph.load
读取持久 next_node"] MODEL["modules/agent_runtime/runtime.py
build_graph.model
模型请求前后复验"] LOCKED["modules/agent_runtime/runtime.py
locked_run
身份、控制权、租约与期限检查"] AUTH["modules/identity/auth.py
authenticate_hash
重新验证持久会话"] STORE["modules/identity/auth.py
authorize_store
重新检查 orders:read"] ACCESS[("modules/identity/access_models.py
AccessSession / StoreGrant
当前会话与权限记录")] API --> QUEUE QUEUE -.->|API 事务提交| RUN WORKER --> CLAIM RUN -.->|跨进程数据库领取| CLAIM WORKER -->|领取成功后| BUILD WORKER --> INVOKE BUILD -.->|注册 load 节点| LOAD BUILD -.->|注册 model 节点| MODEL INVOKE -->|LangGraph 框架调用 START 后的 load| LOAD INVOKE -->|LangGraph 框架调用;条件路由 next_node=model| MODEL LOAD --> LOCKED MODEL -->|模型请求前及保存响应前| LOCKED RUN -.->|读取身份摘要并锁定当前运行| LOCKED LOCKED --> AUTH LOCKED -->|核对运行身份、控制权和租约后| STORE ACCESS -.->|读取当前状态| AUTH ACCESS -.->|读取当前权限| STORE ``` 图中选择 `load` 和 `model` 展示复验时机。工具子图的 `execute` 与 `followup` 节点也调用 `locked_run`。`locked_run` 检查 token 对应身份与 `AgentRun` 一致;有关联会话时检查 `control_owner`、`control_version` 和 `active_run_id`;随后确认 `RUNNING` 状态、有效租约、执行期限、图版本及店铺授权。 模型请求结束后先独立保存已经发生的用量,再复验身份与控制权并提交响应。身份失效等异常由 `execute_one` 记录到当前运行;它只在自己仍持有对应租约时修改运行状态。 ### 图 2 源码导航 - [enqueue](G:/leon/miaoa/workspace/shuh-ai/zhifu-platform/src/zhifu/modules/agent_runtime/api.py:60)、[queue_run](G:/leon/miaoa/workspace/shuh-ai/zhifu-platform/src/zhifu/modules/agent_runtime/service.py:20)、[AgentRun](G:/leon/miaoa/workspace/shuh-ai/zhifu-platform/src/zhifu/modules/agent_runtime/models.py:10):核对 `tenant_id`、`actor_id`、`store_id`、`token_hash` 的保存来源。 - [execute_one](G:/leon/miaoa/workspace/shuh-ai/zhifu-platform/src/zhifu/modules/agent_runtime/worker.py:137)、[claim](G:/leon/miaoa/workspace/shuh-ai/zhifu-platform/src/zhifu/modules/agent_runtime/worker.py:28)、[execute_one.invoke](G:/leon/miaoa/workspace/shuh-ai/zhifu-platform/src/zhifu/modules/agent_runtime/worker.py:165)。 - [build_graph](G:/leon/miaoa/workspace/shuh-ai/zhifu-platform/src/zhifu/modules/agent_runtime/runtime.py:244)、[load](G:/leon/miaoa/workspace/shuh-ai/zhifu-platform/src/zhifu/modules/agent_runtime/runtime.py:247)、[model](G:/leon/miaoa/workspace/shuh-ai/zhifu-platform/src/zhifu/modules/agent_runtime/runtime.py:284)、[节点注册与条件路由](G:/leon/miaoa/workspace/shuh-ai/zhifu-platform/src/zhifu/modules/agent_runtime/runtime.py:412)。 - [locked_run](G:/leon/miaoa/workspace/shuh-ai/zhifu-platform/src/zhifu/modules/agent_runtime/runtime.py:47)、[工具子图 execute](G:/leon/miaoa/workspace/shuh-ai/zhifu-platform/src/zhifu/modules/agent_runtime/runtime.py:96)、[followup](G:/leon/miaoa/workspace/shuh-ai/zhifu-platform/src/zhifu/modules/agent_runtime/runtime.py:252)。 - [履约 prepare](G:/leon/miaoa/workspace/shuh-ai/zhifu-platform/src/zhifu/modules/integrations/fulfillment.py:85) 直接读取 `Tenant`、`Store`、`Principal`、`StoreGrant`,重新检查审批员工的当前权限。该业务事件路径见[路线 03 的图 2](G:/leon/miaoa/workspace/shuh-ai/zhifu-platform/docs/reading-routes/03-after-sales.md)。 ## 图 3:平台员工的独立身份 平台登录入口使用 `PlatformAccount` 和 `PlatformSession`。平台请求的 `authenticate` 在平台会话表中寻找凭据,并检查账户启用状态及 `platform:manage`。 ```mermaid flowchart TB HTTP["FastAPI
/openapi/v1/platform/auth"] LOGIN["modules/platform/auth.py
login
平台账户密码验证与限流"] ACCOUNT[("modules/platform/models.py
PlatformAccount
平台账户与 permissions")] SESSION[("modules/platform/models.py
PlatformSession
平台 token 摘要与有效期")] ME["modules/platform/auth.py
me
查询当前平台身份"] LOGOUT["modules/platform/auth.py
logout
撤销当前平台会话"] AUTH["modules/platform/auth.py
authenticate
检查平台会话与 platform:manage"] HTTP -->|框架调用 POST /sessions| LOGIN HTTP -->|框架调用 GET /me| ME HTTP -->|框架调用 DELETE /sessions/current| LOGOUT ACCOUNT -.->|查询密码摘要并重新核对状态和权限| LOGIN LOGIN -.->|事务保存独立会话| SESSION ME --> AUTH LOGOUT --> AUTH SESSION -.->|读取并重新刷新| AUTH ACCOUNT -.->|锁定账户并校验权限| AUTH LOGOUT -.->|认证成功后设置 revoked=True| SESSION ``` 平台登录成功后同样返回 3600 秒 token。`authenticate` 通过 `PlatformSession.account_id` 找到平台账户,锁定账户后再次刷新会话;随后检查当前 `permissions` 是否包含 `platform:manage`。`me` 返回 `kind=PLATFORM`,退出操作仅撤销本次平台会话。 ### 图 3 源码导航 - [平台 login](G:/leon/miaoa/workspace/shuh-ai/zhifu-platform/src/zhifu/modules/platform/auth.py:44)、[平台 authenticate](G:/leon/miaoa/workspace/shuh-ai/zhifu-platform/src/zhifu/modules/platform/auth.py:20)。 - [PlatformAccount](G:/leon/miaoa/workspace/shuh-ai/zhifu-platform/src/zhifu/modules/platform/models.py:10)、[PlatformSession](G:/leon/miaoa/workspace/shuh-ai/zhifu-platform/src/zhifu/modules/platform/models.py:23)。 - [平台 me](G:/leon/miaoa/workspace/shuh-ai/zhifu-platform/src/zhifu/modules/platform/auth.py:91)、[平台 logout](G:/leon/miaoa/workspace/shuh-ai/zhifu-platform/src/zhifu/modules/platform/auth.py:106)。 ## 关键数据与状态 - `Principal.kind` 包含 `CUSTOMER`、`STAFF`、`SERVICE`;客服、主管和商家管理员的具体职责通过店铺权限表达。可阅读 [ROLE_PERMISSIONS 与 management_access](G:/leon/miaoa/workspace/shuh-ai/zhifu-platform/src/zhifu/modules/merchant/service.py:22) 理解管理入口的身份检查。 - `StoreGrant` 的四个主键字段共同限定权限。资源读取同时受 `tenant_id`、店铺权限和客户归属约束。 - `AccessSession` 保存 `token_hash`、`tenant_id`、`principal_id`、`expires_at`、`revoked`。`authenticate_hash` 从当前记录构建 `AuthContext`。 - 租户和账户需要处于 `ACTIVE`。有效 token 对应的账户或租户停用后,后续身份检查返回 401;业务资源授权不足时,相关入口返回 404。 - `AgentRun` 保存原始身份摘要和执行控制信息。`lease_token` 与 `lease_until` 限制工作进程提交权;关联会话的控制版本限制会话接管后的继续执行。 - `PlatformAccount` 和 `PlatformSession` 管理平台员工身份;平台权限通过 `PlatformAccount.permissions` 检查。 ## 阅读检查问题 1. 查询工单时,租户范围、店铺权限和客户本人归属分别在哪个函数检查?这些检查需要哪些字段? 2. Agent 任务已经进入队列之后,客户退出登录或客服接管会话,哪些检查会阻止工作进程继续保存响应?模型用量为什么另行保存? 3. 平台员工 token 在哪张表中验证?撤销平台会话与撤销客户会话分别修改什么记录? ## 相关测试阅读入口 本路线只阅读测试代码,未执行下列用例。 - [test_confirmation_approval_and_isolation](G:/leon/miaoa/workspace/shuh-ai/zhifu-platform/tests/test_after_sales.py:298):客户确认、审批身份与租户访问范围。 - [test_permission_revocation_and_logout](G:/leon/miaoa/workspace/shuh-ai/zhifu-platform/tests/test_after_sales.py:392):撤销店铺权限与退出当前会话后的响应。 - [test_tool_cannot_read_another_customer_order](G:/leon/miaoa/workspace/shuh-ai/zhifu-platform/tests/test_agent_runtime.py:93)、[test_revoked_session_stops_tool_execution](G:/leon/miaoa/workspace/shuh-ai/zhifu-platform/tests/test_agent_runtime.py:106):后台工具访问客户订单及会话撤销检查。 - [test_revoked_approval_permission_prevents_external_operation](G:/leon/miaoa/workspace/shuh-ai/zhifu-platform/tests/test_fulfillment.py:302):履约准备阶段读取当前审批权限。 - [test_platform_identity_quota_and_audit](G:/leon/miaoa/workspace/shuh-ai/zhifu-platform/tests/test_platform_management.py:92):平台独立会话检查及租户停用后的身份验证。