ThinkPHP 8授权审计日志需构建可追溯、可归责、结构化链路:一明确动态规则驱动的审计范围;二稳定提取用户主体与域名上下文;三记录脱敏快照等结构化内容;四异步写入并建联合索引支撑回溯。

ThinkPHP 8 添加授权审计日志,核心不是“加一条 Log::info()”,而是构建可追溯、可归责、结构化且不干扰主流程的审计链路。重点在于:谁(用户)、在什么上下文(域名/应用)、执行了什么敏感动作(带语义)、操作了哪些关键数据(脱敏+快照)、结果是否成功。
以下四步落地即可形成合规可用的授权审计能力:
明确哪些操作需要审计
硬编码判断动作类型极易遗漏或误判。应采用动态规则驱动:
- 建表
audit_rules,字段包括rule_path(如admin/user/delete)、level(1=普通,2=高危)、desc(如“删除用户主数据”) - 中间件中用
$request->rule()->getRuleName()获取当前路由标识,查表匹配是否命中审计规则 - 跳过登录、登出、验证码等免审接口:
in_array($request->action(), ['login', 'logout', 'captcha'])
稳定提取操作主体与上下文
不能依赖 session 或 cookie 直接读取,要分场景兜底:
- 优先用
Auth::id()(确保 Auth 已初始化) - JWT 场景下,前置中间件已将用户写入请求属性:
$request->attr('user')['id'] - 兜底读
X-User-IDHeader,但必须校验其与当前 token 或 session 的关联性,不可直信 - 二级域名场景下,在 AppInit 中用
$request->host()提取子域名,注入$request->withParam('domain_context', 'admin')
记录结构化、脱敏、可索引的日志内容
拒绝只记 URL 和 IP —— 这类日志无法回答“谁删了哪个用户”。必须包含:
-
user_id(整型,非字符串) -
domain(来自domain_context,用于多域名隔离) -
action(如admin/user/delete,非方法名) -
params(仅保留业务关键字段:array_intersect_key($params, array_flip(['id', 'status', 'role_id'])),显式剔除password等) -
before_data(高危操作启用:如UserModel::find($params['id'])取出用户名、邮箱、状态等快照) -
ip(VARCHAR(45),兼容 IPv6) -
session_id(用于行为串联)
异步写入独立存储,避免拖垮主流程
- 日志写入必须脱离主事务,推荐使用队列(如 think-queue)或数据库连接池外的独立连接
- 数据库表需建联合索引:
(user_id, domain, action, create_time),支撑按人、按域、按动作快速回溯 - 表结构字段建议含
id,user_id,username,domain,action,params,before_data,ip,session_id,status,create_time
不复杂但容易忽略。
立即学习“PHP免费学习笔记(深入)”;



















