ThinkPHP 5.1需通过自定义中间件(如AuthLogMiddleware)在鉴权关键点捕获用户ID、动作、状态、原因等结构化字段,脱敏记录至独立日志或数据库,区分登录/失败场景并配置分级开关,同时补充异常钩子覆盖Token过期等边界情况。

ThinkPHP 5.1 本身不自动记录授权(如登录、权限校验、Token 验证等)行为,必须通过中间件主动捕获关键节点并写入结构化日志。重点不是“加个 Log::info()”,而是确保日志含用户身份、授权动作、结果状态和上下文,同时避开敏感信息与性能干扰。
一、用中间件统一拦截授权关键点
授权日志最可靠的位置是鉴权中间件(如登录验证、JWT 拦截、RBAC 权限检查),而非分散在控制器或模型中。推荐新建 App\Middleware\AuthLogMiddleware:
- 在
handle()开头判断是否进入授权流程:比如请求路径匹配/login、/api/token/refresh,或检测到Authorization头、token参数 - 若命中,提取关键字段:
user_id(登录成功后才有)、action(如'login'、'check_permission'、'token_invalid')、status(success或failed)、reason(失败原因,如'password_error'、'permission_denied') - 跳过静态资源(
.js、.css、/public/)和健康接口(/ping、/health),避免日志刷爆
二、日志内容必须脱敏且结构清晰
授权过程常涉及密码、Token、手机号等,严禁原样写入。建议使用 JSON 行格式写入独立文件,例如 runtime/log/auth/2026-08-27.log:
- 显式过滤敏感字段:从
$request->param()中unset('password', 'token', 'refresh_token') - 只记录必要参数:如登录时记
['username' => 'admin', 'ip' => '192.168.1.100'],权限拒绝时记['route' => 'admin/user/delete', 'required_role' => 'super_admin'] - 写入前加
flock()锁,防止并发写丢失;生产环境更建议存入数据库或 Redis,而非纯文件
三、区分授权类型,按需启用开关
不是所有授权都要记全量日志。可在配置中分级控制:
立即学习“PHP免费学习笔记(深入)”;
- 在
config/auth.php添加:'log_level' => ['login', 'failed_auth'],只记录登录和失败场景,忽略每次成功的权限校验 - 开发环境可设为
['all'],上线后收缩范围,降低 I/O 压力 - 对高频接口(如菜单权限校验),增加简单计数器或采样率(如每 100 次记 1 次),避免拖慢响应
四、配合框架异常机制补全边界情况
有些授权失败不会走中间件(如 Token 过期被中间件前置拦截、401 响应直接返回),需补充钩子:
- 在
app/exception/Handle.php的render()方法中,识别TokenExpiredException、UnauthorizedHttpException等,并调用统一日志方法 - 若使用
think\facade\Auth,可在其事件监听(如Auth::event('login_success'))中触发日志,但注意 TP5.1 原生 Auth 不自带事件,需自行扩展或改用中间件 - 确保日志能覆盖“未登录就访问受保护接口”的场景——此时
user_id为空,但status和reason必须明确,例如{ "status": "failed", "reason": "no_auth_header" }



















