<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>安全 on Saiga</title>
    <link>http://localhost:1313/tags/%E5%AE%89%E5%85%A8/</link>
    <description>Recent content in 安全 on Saiga</description>
    <generator>Hugo</generator>
    <language>zh-cn</language>
    <managingEditor>wuwenzen@outlook.com (wuwj)</managingEditor>
    <webMaster>wuwenzen@outlook.com (wuwj)</webMaster>
    <lastBuildDate>Tue, 25 Mar 2025 00:00:00 +0000</lastBuildDate>
    <atom:link href="http://localhost:1313/tags/%E5%AE%89%E5%85%A8/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>金融业务系统的前端权限与操作可追溯：设计要点与落地方式</title>
      <link>http://localhost:1313/posts/2025-03-25-fintech-frontend-permission-and-audit/</link>
      <pubDate>Tue, 25 Mar 2025 00:00:00 +0000</pubDate><author>wuwenzen@outlook.com (wuwj)</author>
      <guid>http://localhost:1313/posts/2025-03-25-fintech-frontend-permission-and-audit/</guid>
      <description>&lt;h2 id=&#34;背景&#34;&gt;背景&lt;/h2&gt;&#xA;&lt;p&gt;在金融业务系统中，“能不能做”与“做了什么”通常同等重要：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;权限需要细粒度（页面、模块、动作）&lt;/li&gt;&#xA;&lt;li&gt;高风险操作需要二次确认与留痕&lt;/li&gt;&#xA;&lt;li&gt;线上问题需要可追溯（谁、在何时、做了什么）&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;前端并非审计的最终来源，但前端是“入口层”，对降低误操作与提升可追溯性非常关键。&lt;/p&gt;&#xA;&lt;hr&gt;&#xA;&lt;h2 id=&#34;1-权限模型动作权限作为最小单元&#34;&gt;1. 权限模型：动作权限作为最小单元&lt;/h2&gt;&#xA;&lt;p&gt;推荐以“动作权限”作为最小单元（而不是只做菜单/页面）：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-json&#34; data-lang=&#34;json&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;resource&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;order:review&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;actions&amp;#34;&lt;/span&gt;: [&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;view&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;approve&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;reject&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;export&amp;#34;&lt;/span&gt;]&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;落地到前端的三层控制：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;路由守卫：控制页面是否可进入&lt;/li&gt;&#xA;&lt;li&gt;组件/指令：控制按钮、入口是否可见/可用&lt;/li&gt;&#xA;&lt;li&gt;请求层兜底：对敏感接口做二次校验（避免绕过 UI）&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;hr&gt;&#xA;&lt;h2 id=&#34;2-操作风险分级不同级别用不同交互&#34;&gt;2. 操作风险分级：不同级别用不同交互&lt;/h2&gt;&#xA;&lt;p&gt;建议对操作做风险分级（示例）：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;低风险：查询、查看详情&lt;/li&gt;&#xA;&lt;li&gt;中风险：提交、发起流程、修改关键字段&lt;/li&gt;&#xA;&lt;li&gt;高风险：审批通过、批量处理、导出敏感数据&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;不同级别对应不同交互策略：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;中风险：二次确认 + 明确影响范围&lt;/li&gt;&#xA;&lt;li&gt;高风险：强确认（输入关键字/再次校验）+ 明确告知留痕&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;hr&gt;&#xA;&lt;h2 id=&#34;3-操作留痕前端如何参与可追溯&#34;&gt;3. 操作留痕：前端如何参与“可追溯”&lt;/h2&gt;&#xA;&lt;p&gt;前端侧建议做三件事：&lt;/p&gt;&#xA;&lt;h3 id=&#34;31-为关键动作生成-traceid&#34;&gt;3.1 为关键动作生成 traceId&lt;/h3&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;每次关键操作生成 &lt;code&gt;traceId&lt;/code&gt;&lt;/li&gt;&#xA;&lt;li&gt;随请求携带到后端&lt;/li&gt;&#xA;&lt;li&gt;前后端日志用同一 traceId 串联&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;32-标准化审计字段脱敏&#34;&gt;3.2 标准化审计字段（脱敏）&lt;/h3&gt;&#xA;&lt;p&gt;建议上报结构化字段：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;action（动作编码）&lt;/li&gt;&#xA;&lt;li&gt;resource（资源编码）&lt;/li&gt;&#xA;&lt;li&gt;targetId（业务对象 id）&lt;/li&gt;&#xA;&lt;li&gt;result（success/fail）&lt;/li&gt;&#xA;&lt;li&gt;reason（失败原因码）&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;避免：把敏感字段明文写入日志/埋点。&lt;/p&gt;&#xA;&lt;h3 id=&#34;33-失败也要可追溯&#34;&gt;3.3 失败也要可追溯&lt;/h3&gt;&#xA;&lt;p&gt;很多事故来自失败重试与重复提交：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;失败原因要可读（错误码映射）&lt;/li&gt;&#xA;&lt;li&gt;可操作指引要明确（下一步做什么）&lt;/li&gt;&#xA;&lt;li&gt;必要时提供“一键复制 traceId”入口，方便支持排查&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;hr&gt;&#xA;&lt;h2 id=&#34;4-误操作防护前端的最后一道门&#34;&gt;4. 误操作防护：前端的“最后一道门”&lt;/h2&gt;&#xA;&lt;p&gt;常见防护手段：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;按钮防抖 + 请求幂等 key（避免重复提交）&lt;/li&gt;&#xA;&lt;li&gt;表单关键字段修改提示（脏数据提示）&lt;/li&gt;&#xA;&lt;li&gt;高风险操作的预检查（权限、状态、前置条件）&lt;/li&gt;&#xA;&lt;li&gt;批量操作的预览（影响范围、条数、筛选条件回显）&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;hr&gt;&#xA;&lt;h2 id=&#34;5-可维护性权限与路由不要绑死在页面&#34;&gt;5. 可维护性：权限与路由不要绑死在页面&lt;/h2&gt;&#xA;&lt;p&gt;建议将权限控制抽象成“能力层”：&lt;/p&gt;</description>
    </item>
    <item>
      <title>调用大模型 API 的几个最佳实践：重试、降级与审计</title>
      <link>http://localhost:1313/posts/2023-06-05-ai-api-best-practices/</link>
      <pubDate>Mon, 05 Jun 2023 00:00:00 +0000</pubDate><author>wuwenzen@outlook.com (wuwj)</author>
      <guid>http://localhost:1313/posts/2023-06-05-ai-api-best-practices/</guid>
      <description>&lt;p&gt;刚开始用大模型 API 时，大家一般关心的是：&lt;/p&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;这个模型效果好不好？回答聪不聪明？&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;p&gt;但当你真的把它作为「线上能力」接入产品时，会发现很多工程问题：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;API 偶尔超时 / 报错怎么办？&lt;/li&gt;&#xA;&lt;li&gt;费用怎么控？&lt;/li&gt;&#xA;&lt;li&gt;返回内容里如果有敏感信息怎么办？&lt;/li&gt;&#xA;&lt;li&gt;出了问题，怎么排查某次请求？&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;这篇文章就是从这些「落地问题」出发，整理几条接入大模型 API 的最佳实践。&lt;/p&gt;&#xA;&lt;hr&gt;&#xA;&lt;h2 id=&#34;1-超时与重试别把前端一直挂着&#34;&gt;1. 超时与重试：别把前端一直挂着&lt;/h2&gt;&#xA;&lt;h3 id=&#34;11-超时要有明确上限&#34;&gt;1.1 超时要有明确上限&lt;/h3&gt;&#xA;&lt;p&gt;大模型生成本身需要时间，如果不设超时，前端可能会一直转圈。&lt;br&gt;&#xA;我们一般做法：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;在 BFF / 中间层对每个调用设定超时时间（例如 10–15 秒）；&lt;/li&gt;&#xA;&lt;li&gt;超时后直接返回「超时错误」，由前端给出友好提示；&lt;/li&gt;&#xA;&lt;li&gt;前端也设置请求超时，避免被挂死。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;12-重试策略&#34;&gt;1.2 重试策略&lt;/h3&gt;&#xA;&lt;p&gt;常见错误类型：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;临时网络抖动；&lt;/li&gt;&#xA;&lt;li&gt;API 限流（429）；&lt;/li&gt;&#xA;&lt;li&gt;服务端偶发异常。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;对&lt;strong&gt;幂等请求&lt;/strong&gt;（比如生成建议文案），我们采用：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;指数退避重试&lt;/strong&gt;：例如最多重试 2 次，间隔 500ms / 1000ms；&lt;/li&gt;&#xA;&lt;li&gt;遇到某些错误码（如 4xx 中的参数错误）不重试。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;伪代码：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-ts&#34; data-lang=&#34;ts&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;async&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;function&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;callLLMWithRetry&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;payload&lt;/span&gt;) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;const&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;maxRetry&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;attempt&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;while&lt;/span&gt; (&lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;try&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;await&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;callLLM&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;payload&lt;/span&gt;);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    } &lt;span style=&#34;color:#66d9ef&#34;&gt;catch&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;e&lt;/span&gt;: &lt;span style=&#34;color:#66d9ef&#34;&gt;any&lt;/span&gt;) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#f92672&#34;&gt;!&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;isRetryableError&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;e&lt;/span&gt;) &lt;span style=&#34;color:#f92672&#34;&gt;||&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;attempt&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;maxRetry&lt;/span&gt;) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;throw&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;e&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#a6e22e&#34;&gt;attempt&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;++&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#66d9ef&#34;&gt;await&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;sleep&lt;/span&gt;(&lt;span style=&#34;color:#ae81ff&#34;&gt;500&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;attempt&lt;/span&gt;);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;&#xA;&lt;h2 id=&#34;2-降级模型不可用时要有备胎&#34;&gt;2. 降级：模型不可用时要有「备胎」&lt;/h2&gt;&#xA;&lt;p&gt;大模型 API 作为外部依赖，不可能 100% 可用。&lt;br&gt;&#xA;因此建议设计「降级方案」：&lt;/p&gt;</description>
    </item>
  </channel>
</rss>
