2026-09-09 23:22:59 +08:00
|
|
|
|
<section class="module" id="module-3">
|
|
|
|
|
|
<div class="module-inner">
|
|
|
|
|
|
<p class="eyebrow animate-in">模块 3 · 出参脱敏</p>
|
|
|
|
|
|
<h1 class="module-title animate-in">PLATFORM_RESPONSE_DESENSITIZE:<br>模拟库原样,真库再遮</h1>
|
|
|
|
|
|
<p class="module-lead animate-in">
|
|
|
|
|
|
环境变量
|
|
|
|
|
|
<code>PLATFORM_RESPONSE_DESENSITIZE</code>
|
|
|
|
|
|
控制平台 API 出参是否打码姓名/手机/证件。
|
|
|
|
|
|
v0.1 默认<strong>关</strong>——本地 Core 模拟库联调看原值;接真 Core 再开,在
|
|
|
|
|
|
<span class="term" data-definition="Service 层 = 业务组装层,REST 和日后 Agent Tool 共用,避免两处各写一套脱敏逻辑。">Platform Service</span>
|
|
|
|
|
|
统一出口处理。
|
|
|
|
|
|
</p>
|
|
|
|
|
|
|
|
|
|
|
|
<div class="screen animate-in">
|
|
|
|
|
|
<h2>开关行为一览</h2>
|
|
|
|
|
|
<table style="width:100%; border-collapse:collapse; margin: 1.5rem 0; font-size: 0.95rem;">
|
|
|
|
|
|
<thead><tr><th>开关</th><th>模拟库联调</th><th>生产 / 真 Core</th></tr></thead>
|
|
|
|
|
|
<tbody>
|
|
|
|
|
|
<tr><td><code>false</code>(默认)</td><td>L0 字段原样返回</td><td>—</td></tr>
|
|
|
|
|
|
<tr><td><code>true</code></td><td>—</td><td>姓名/手机/证件/银行卡打码;<code>customer_id</code> 不脱敏</td></tr>
|
|
|
|
|
|
</tbody>
|
|
|
|
|
|
</table>
|
|
|
|
|
|
<div class="callout callout-accent">
|
2026-09-10 10:57:40 +08:00
|
|
|
|
<strong>实现位置:</strong> 响应脱敏(<code>app/service/platform/common.py</code>)的 <code>maybe_desensitize_row</code> → <code>prepare_row</code>。REST 与 Agent 适配层都应走这里,不要在路由里手写 mask。
|
2026-09-09 23:22:59 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<div class="screen animate-in">
|
|
|
|
|
|
<div class="translation-block">
|
|
|
|
|
|
<div class="translation-code">
|
2026-09-10 10:57:40 +08:00
|
|
|
|
<span class="translation-label">响应脱敏(platform/common.py)</span>
|
2026-09-09 23:22:59 +08:00
|
|
|
|
<pre><code><span class="code-line"><span class="code-keyword">def</span> <span class="code-function">maybe_desensitize_row</span>(row: dict | None) -> dict | None:</span>
|
|
|
|
|
|
<span class="code-line"> <span class="code-keyword">if</span> row <span class="code-keyword">is</span> None <span class="code-keyword">or not</span> settings.platform_response_desensitize:</span>
|
|
|
|
|
|
<span class="code-line"> <span class="code-keyword">return</span> row</span>
|
|
|
|
|
|
<span class="code-line"> <span class="code-keyword">for</span> key, masker <span class="code-keyword">in</span> (</span>
|
|
|
|
|
|
<span class="code-line"> (<span class="code-string">"display_name"</span>, d.mask_name),</span>
|
|
|
|
|
|
<span class="code-line"> (<span class="code-string">"mobile_phone"</span>, d.mask_phone),</span>
|
|
|
|
|
|
<span class="code-line"> (<span class="code-string">"id_card_no"</span>, d.mask_id_card),</span>
|
|
|
|
|
|
<span class="code-line"> ...</span>
|
|
|
|
|
|
<span class="code-line"> ): ...</span>
|
|
|
|
|
|
<span class="code-line"><span class="code-keyword">def</span> <span class="code-function">prepare_row</span>(row):</span>
|
|
|
|
|
|
<span class="code-line"> <span class="code-keyword">return</span> to_jsonable(maybe_desensitize_row(row) or row)</span></code></pre>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="translation-english">
|
|
|
|
|
|
<span class="translation-label">白话</span>
|
|
|
|
|
|
<div class="translation-lines">
|
|
|
|
|
|
<p class="tl">开关关着 → 数据库行原样返回,方便本地对账。</p>
|
|
|
|
|
|
<p class="tl">开关开着 → 按字段名找 mask 函数,逐个打码。</p>
|
|
|
|
|
|
<p class="tl">prepare_row 是统一出口:先脱敏,再把 Decimal/日期转成 JSON 能序列化的类型。</p>
|
|
|
|
|
|
<p class="tl">指挥 AI 加新字段时,若含 PII,记得在这里登记 masker。</p>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<div class="screen animate-in">
|
|
|
|
|
|
<h2>自检:你能否指挥 AI 正确切换?</h2>
|
|
|
|
|
|
<div class="quiz-container" id="quiz-platform-m3">
|
|
|
|
|
|
<div class="quiz-question-block"
|
|
|
|
|
|
data-correct="option-c"
|
|
|
|
|
|
data-explanation-right="对。默认 false 是为了模拟库联调;上真库时在 .env 设 PLATFORM_RESPONSE_DESENSITIZE=true,脱敏在 Service 层自动生效。"
|
2026-09-10 10:57:40 +08:00
|
|
|
|
data-explanation-wrong="不要在每个路由里 copy 打码逻辑;开关在 settings,行为在 响应脱敏(platform/common.py)。">
|
2026-09-09 23:22:59 +08:00
|
|
|
|
<h3 class="quiz-question">准备接真 Core,要让出参打码手机号,最省事的做法是?</h3>
|
|
|
|
|
|
<div class="quiz-options">
|
|
|
|
|
|
<button class="quiz-option" data-value="option-a" onclick="selectOption(this)">
|
2026-09-10 10:57:40 +08:00
|
|
|
|
<div class="quiz-option-radio"></div><span>在平台客户 REST 薄路由(customers.py)返回前手写 replace</span>
|
2026-09-09 23:22:59 +08:00
|
|
|
|
</button>
|
|
|
|
|
|
<button class="quiz-option" data-value="option-b" onclick="selectOption(this)">
|
|
|
|
|
|
<div class="quiz-option-radio"></div><span>让前端自己 mask 手机号</span>
|
|
|
|
|
|
</button>
|
|
|
|
|
|
<button class="quiz-option" data-value="option-c" onclick="selectOption(this)">
|
|
|
|
|
|
<div class="quiz-option-radio"></div><span>.env 设 PLATFORM_RESPONSE_DESENSITIZE=true</span>
|
|
|
|
|
|
</button>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="quiz-feedback"></div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="quiz-question-block"
|
|
|
|
|
|
data-correct="option-b"
|
|
|
|
|
|
data-explanation-right="customer_id 是业务主键,联调和归属校验都要用,契约明确不脱敏。"
|
|
|
|
|
|
data-explanation-wrong="customer_id 不在 mask 列表里,脱敏只覆盖姓名/手机/证件/银行卡等 PII 字段。">
|
|
|
|
|
|
<h3 class="quiz-question">脱敏开启后,customer_id 会被打码吗?</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>不会,customer_id 保留原值</span>
|
|
|
|
|
|
</button>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="quiz-feedback"></div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<button class="quiz-check-btn" onclick="checkQuiz('quiz-platform-m3')">检查答案</button>
|
|
|
|
|
|
<button class="quiz-reset-btn" onclick="resetQuiz('quiz-platform-m3')">重做</button>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</section>
|