ThinkPHP 6 的 Request 不自动脱敏,须在响应输出前通过 Response::withOutput 统一处理,支持配置化、递归式字段路径匹配与 JSON 安全编码。

ThinkPHP 6 的 think\facade\Request 不会自动脱敏,必须手动介入
ThinkPHP 默认对请求数据($request->param()、$request->post() 等)不做任何脱敏处理。所谓“自动脱敏”,本质是拦截原始输入,在序列化/响应前做字段替换。别指望中间件或验证器能覆盖所有出口——比如 json()、success()、return $data 这些直出场景最容易漏掉。
常见错误现象:手机号显示为 138****1234 在列表页正常,但导出 Excel 或 API 调试时又变成明文;或者脱敏逻辑写在控制器里,结果模型关联查询返回的嵌套数组完全没走脱敏。
- 脱敏必须发生在「数据组装完成、序列化开始前」这个时间点,最佳位置是响应输出前的统一钩子
- 不要在验证器里改
$data—— 验证器只负责校验,改了会影响后续业务逻辑判断 - 避免用
str_replace全局扫字符串,容易误伤 ID、金额、URL 等非敏感字段
用 think\Response 的 withOutput 扩展实现响应级脱敏
ThinkPHP 6 的 Response 类支持 withOutput 方法注册回调,它会在最终调用 send() 前执行,且接收的是已组装好的响应内容(JSON 字符串或 HTML 字符串),是真正意义上的“最后一道关卡”。
使用场景:API 接口统一返回 JSON、前后端分离项目、需兼容 Swagger 调试等——只要响应体是 JSON,就能稳稳兜住。
立即学习“PHP免费学习笔记(深入)”;
- 在
app/common.php或中间件中注册:think\Response::withOutput(function ($content) { if (request()->isAjax() && strpos(request()->header('accept'), 'json') !== false) { $data = json_decode($content, true); if (is_array($data)) { $data = \app\common\helper\Desensitize::handle($data); return json_encode($data, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES); } } return $content; }); - 注意:该回调不处理文件下载、重定向、HTML 页面等非 JSON 响应,别试图在这里处理模板渲染
-
withOutput是全局生效的,若某些接口(如支付回调)明确禁止脱敏,得在回调内部加白名单判断
Desensitize::handle() 必须支持嵌套与配置驱动,不能硬编码字段名
硬写 if ($key === 'phone') { $val = substr($val, 0, 3) . '****' . substr($val, -4); } 看似快,但一遇到 user.profile.phone、list.0.contact.mobile 就失效。脱敏规则必须可配置、可递归、可跳过指定层级。
参数差异体现在字段路径匹配方式上:用点号分隔的路径(user.phone)比正则更可控,也比简单 key 匹配更安全。
- 推荐配置存于
config/desensitize.php:return [ 'rules' => [ 'user.phone' => ['type' => 'mobile'], 'user.id_card' => ['type' => 'idcard'], 'order.pay_no' => ['type' => 'custom', 'mask' => '***'], ], 'skip_keys' => ['token', 'sign', 'signature'] ]; - 递归处理时,传入当前路径(如
user.address.city),逐级比对配置中的user.phone是否为前缀匹配 - 性能影响很小——一次请求最多遍历几百个字段,但别在
handle()里做 DB 查询或远程 HTTP 调用
脱敏后 JSON 编码失败?检查 json_encode 的第三个参数和中文处理
常见错误现象:json_encode() 返回 false,响应变成空字符串或 500;或中文变 \uXXXX,前端显示乱码。这通常不是脱敏逻辑问题,而是编码环节失控。
ThinkPHP 默认用 JSON_UNESCAPED_UNICODE,但如果你在 withOutput 回调里手动 json_encode 却漏了它,就会触发默认转义。
- 务必带上
JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES,否则斜杠被转义可能破坏 URL 字段 - 如果脱敏后出现
null,先用var_dump(json_last_error_msg())查错,90% 是字段含资源类型(如mysqli_result)或不可序列化对象,不是脱敏导致的 - 别在脱敏函数里直接
echo或exit,会中断withOutput流程,导致响应头已发送但内容为空



















