Files
group_xinghuo_jinrong/docs/course/jinrong-module-platform/modules/02-auth-flow.html
T
zhanghongyu_0626 6f222f1c56 feat(course): Add course assembly script and module structure for advisor training
- Introduced `build_all.py` script to automate the assembly of course modules into a single `index.html` file.
- Created `index.html` for the main course overview, featuring a structured layout and navigation for various modules.
- Developed `_base.html` and `_footer.html` templates for the advisor module, ensuring consistent styling and structure.
- Added `build.sh` script for individual module assembly, enhancing modularity and ease of updates.
- Implemented multiple module HTML files detailing specific training scenarios and functionalities for advisors, including interactive elements and quizzes.

This update significantly enhances the course delivery framework, providing a comprehensive and interactive learning experience for advisors.
2026-09-09 23:22:59 +08:00

127 lines
7.6 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<section class="module" id="module-2">
<div class="module-inner">
<p class="eyebrow animate-in">模块 2 · 平台鉴权</p>
<h1 class="module-title animate-in">get_platform_auth_context:<br>只要 JWT,不要 X-Agent-Type</h1>
<p class="module-lead animate-in">
对话线(<code>/api/chat</code>)必须带
<span class="term" data-definition="HTTP 请求头里的一行,声明这次走 customer/advisor/risk/analyst 哪条 Agent 业务线。">X-Agent-Type</span>;
平台读 API 故意<strong>不要</strong>——App 和仪表盘只证明「你是谁」,不声明「你在敲哪扇 Agent 窗」。
</p>
<div class="screen animate-in">
<h2>和 chat 鉴权的对照表</h2>
<table style="width:100%; border-collapse:collapse; margin: 1.5rem 0; font-size: 0.95rem;">
<thead><tr><th>场景</th><th>函数</th><th>X-Agent-Type</th><th>归属断言</th></tr></thead>
<tbody>
<tr><td>平台 REST</td><td><code>get_platform_auth_context</code></td><td><strong>不要</strong></td><td><code>assert_platform_customer_access</code></td></tr>
<tr><td>对话 / 风控 REST</td><td><code>get_auth_context</code></td><td><strong>必须</strong></td><td><code>assert_customer_access</code> + 准入矩阵</td></tr>
</tbody>
</table>
<div class="callout callout-warning">
<strong>指挥 AI 接前端时:</strong> <code>apiFetch</code> 读持仓只带 Bearer;若误加 <code>X-Agent-Type: customer</code>,平台路由会忽略,但混进 chat 路由就会多一层校验甚至 401。
</div>
</div>
<div class="screen animate-in">
<h2>群聊:前端问「张三持仓多少」</h2>
<p>理财师工作台发 GET 持仓——只走平台三层,不进 LangGraph。</p>
<div class="chat-window" id="chat-platform-m2">
<div class="chat-messages">
<div class="chat-message" data-msg="0" data-sender="frontend" style="display:none">
<div class="chat-avatar" style="background: var(--color-accent)">🖥</div>
<div class="chat-bubble">
<span class="chat-sender" style="color: var(--color-accent)">前端</span>
<p>GET /api/customers/CUST-1001/holdings<br>Authorization: Bearer eyJ…<br><em>(无 X-Agent-Type)</em></p>
</div>
</div>
<div class="chat-message" data-msg="1" data-sender="api" style="display:none">
<div class="chat-avatar" style="background: #5A9DB8">🚪</div>
<div class="chat-bubble">
<span class="chat-sender" style="color: #5A9DB8">customers.py</span>
<p>Depends(get_platform_auth_context) → JWT 验签 OK<br>assert_platform_customer_access:STAFF-10086 名下有 CUST-1001 ✓</p>
</div>
</div>
<div class="chat-message" data-msg="2" data-sender="service" style="display:none">
<div class="chat-avatar" style="background: #E06B56">📦</div>
<div class="chat-bubble">
<span class="chat-sender" style="color: #E06B56">platform_service</span>
<p>list_holdings(customer_id) → prepare_row 脱敏开关检查 → 分页组装 items</p>
</div>
</div>
<div class="chat-message" data-msg="3" data-sender="core" style="display:none">
<div class="chat-avatar" style="background: #2D8B55">🗄</div>
<div class="chat-bubble">
<span class="chat-sender" style="color: #2D8B55">core_ro</span>
<p>SELECT … FROM holdings WHERE customer_id = ?<br>只读,不写 Core 正式账</p>
</div>
</div>
<div class="chat-message" data-msg="4" data-sender="frontend" style="display:none">
<div class="chat-avatar" style="background: var(--color-accent)">🖥</div>
<div class="chat-bubble">
<span class="chat-sender" style="color: var(--color-accent)">前端</span>
<p>收到 200 + data.items,渲染持仓表。全程没经过 chat.py。</p>
</div>
</div>
</div>
<div class="chat-typing" style="display:none">
<div class="chat-avatar" id="chat-platform-m2-typing-avatar">?</div>
<div class="chat-typing-dots">
<span class="typing-dot"></span><span class="typing-dot"></span><span class="typing-dot"></span>
</div>
</div>
<div class="chat-controls">
<button class="btn chat-next-btn">下一条</button>
<button class="btn chat-all-btn">自动播放</button>
<button class="btn chat-reset-btn">重来</button>
<span class="chat-progress"></span>
</div>
</div>
</div>
<div class="screen animate-in">
<div class="translation-block">
<div class="translation-code">
<span class="translation-label">deps.py</span>
<pre><code><span class="code-line"><span class="code-keyword">def</span> <span class="code-function">get_platform_auth_context</span>(request: Request) -> AuthContext:</span>
<span class="code-line"> <span class="code-string">"""平台 API 鉴权:JWT 通道 **不要求** X-Agent-Type。"""</span></span>
<span class="code-line"> auth_header = request.headers.get(<span class="code-string">"Authorization"</span>, <span class="code-string">""</span>)</span>
<span class="code-line"> <span class="code-keyword">if</span> auth_header[:<span class="code-number">7</span>].lower() == <span class="code-string">"bearer "</span>:</span>
<span class="code-line"> claims = verify_token(token)</span>
<span class="code-line"> <span class="code-keyword">return</span> _bind_state(request, _claims_to_auth(claims))</span>
<span class="code-line"> <span class="code-comment"># dev:X-Debug-Role / X-Debug-Actor 兜底</span></span></code></pre>
</div>
<div class="translation-english">
<span class="translation-label">白话</span>
<div class="translation-lines">
<p class="tl">函数名就写死:平台鉴权,不读 X-Agent-Type。</p>
<p class="tl">有 Bearer 就验 JWT,解析出 actor_id 和 roles。</p>
<p class="tl">本地开发没 JWT 时,可用 debug 头冒充身份(仅 development)。</p>
<p class="tl">和 get_auth_context 不同:后者在 JWT 通道会强制校验 X-Agent-Type + 准入矩阵。</p>
</div>
</div>
</div>
<div class="quiz-container" id="quiz-platform-m2">
<div class="quiz-question-block"
data-correct="option-a"
data-explanation-right="问数 POST /api/analyst/chat 走 get_platform_auth_context,前端 analyst.ts 只带 Bearer。"
data-explanation-wrong="analyst 问数是平台读能力,不是 /api/chat 对话分流,不要 X-Agent-Type。">
<h3 class="quiz-question">分析员「问数工作台」调 /api/analyst/chat,要带 X-Agent-Type: analyst 吗?</h3>
<div class="quiz-options">
<button class="quiz-option" data-value="option-a" onclick="selectOption(this)">
<div class="quiz-option-radio"></div><span>不要,走平台鉴权</span>
</button>
<button class="quiz-option" data-value="option-b" onclick="selectOption(this)">
<div class="quiz-option-radio"></div><span>要,和 ChatPanel 一样</span>
</button>
</div>
<div class="quiz-feedback"></div>
</div>
<button class="quiz-check-btn" onclick="checkQuiz('quiz-platform-m2')">检查答案</button>
<button class="quiz-reset-btn" onclick="resetQuiz('quiz-platform-m2')">重做</button>
</div>
</div>
</div>
</section>