Laravel 的 signed 中间件仅适用于 Web 路由的签名 URL 验证,不支持 API 请求体签名;需为 API 自定义 VerifyApiSignature 中间件,安全读取原始请求体、字典序拼参、HMAC-SHA256 签名校验,并注意时钟同步、密钥正确性及中间件执行顺序。

Laravel 的 signed 中间件是为 Web 路由设计的 URL 签名验证机制,**不适用于 API 场景**。它基于时间戳 + 密钥对完整 URL(含查询参数)生成签名,用于防止链接被篡改或滥用,比如邮件邀请、密码重置等。若你实际想做的是 API 请求体签名(如 JSON 或表单提交),那需要自定义中间件,而非直接用 Laravel 自带的 signed。
什么时候用内置 signed 中间件
适用于带签名参数的 GET 请求链接,例如:
/invite/123?expires=1730050000&signature=abc123...- 签名由
URL::signedRoute()或URL::temporarySignedRoute()生成 - 请求必须走
web中间件组(依赖 session 和加密服务)
怎么在路由中启用
直接在 routes/web.php 中添加 signed 中间件即可:
Route::get('/invite/{id}', [InviteController::class, 'accept'])
->middleware('signed')
->name('invite.accept');
控制器中可调用 $request->hasValidSignature() 手动校验,或直接依赖中间件抛出 403。
API 场景不能用 signed,得自己写中间件
因为 signed 不处理 POST/JSON/请求体,也不支持自定义字段排序、timestamp 验证、nonce 防重放等 API 安全要求。正确做法是:
- 新建中间件:
php artisan make:middleware VerifyApiSignature - 在
handle()开头用$request->instance()->getContent(false)安全读原始请求体 - 按字典序拼接非空参数(排除
signature、_token等),URL 编码后与密钥一起算hash_hmac('sha256', $data, $key) - 注册到
$middlewareGroups['api'],别加进全局堆栈 - 确保放在
ThrottleRequests之前,且不调用$request->user()
常见失败原因
验签总返回 401?检查这几项:
- 请求体是否已被其他中间件(如
TrimStrings、ConvertEmptyStringsToNull)提前消费 - 前端拼参顺序是否和后端
ksort()一致,数组格式是否统一(foo[0]=avsfoo[]=a) - 时间戳是否在允许误差范围内(建议 ±5 秒),且服务端与客户端时钟同步
- 密钥是否从
.env正确读取,未被空格或换行截断











