Laravel URL 处理:URL 签名
问题
我如何防止公开 URL 被篡改?
回答
Laravel 允许你轻松地为命名路由创建 「签名」 URL。这些 URL 在查询字符串后附加了 「签名」哈希,这样 Laravel 就可以验证 URL 自创建以来有没有被修改过。签名 URL 对于可公开访问但需要一层防止 URL 操作的路由特别有用。
生成签名 URL
比如,你可以使用签名 URL 来实现通过电子邮件发送给客户的「取消订阅」链接不被非法篡改。要创建命名路由的签名 URL,可使用 URL 门面的 signedRoute
方法`:
use Illuminate\Support\Facades\URL;
return URL::signedRoute('unsubscribe', ['user' => 1]);
上面代码将返回类似 http://domain.com/unsubscribe?user=1&signature=92af617e07cbdc2620732843928caa550a13c005cdedb7737a0b877895a5721c
这样的 URL。如果更喜欢使用全局辅助函数 url()
,也可以:
return url()->signedRoute('unsubscribe', ['user' => 1]);
如果要生成包含过期信息的临时签名路由 URL,可以使用 temporarySignedRoute
方法:
use Illuminate\Support\Facades\URL;
return URL::temporarySignedRoute(
'unsubscribe', now()->addMinutes(30), ['user' => 1]
);
返回的 URL 类似:http://domain.com/unsubscribe?expires=1559212837&user=1&signature=d4e56e4fad59e0466e611ac61fbcf164443110e200b70a2bb58763801a922d1e
。
验证签名路由请求
要验证传入请求是否具有有效签名,可以调用注入的 Request
实例上的 hasValidSignature
方法:
use Illuminate\Http\Request;
Route::get('/unsubscribe/{user}', function (Request $request) {
if (!$request->hasValidSignature()) {
abort(401);
}
// ...
})->name('unsubscribe');
或可以将 Illuminate\Routing\Middleware\ValidateSignature
中间件分配给路由。如果不存在,则应在 app\Http\Kernel.php
文件的 routeMiddleware
数组中为其分配一个键:
/**
* 应用程序的路由中间件
*
* 这些中间件可能被分配给组或单独使用
*
* @var array
*/
protected $routeMiddleware = [
'signed' => \Illuminate\Routing\Middleware\ValidateSignature::class,
];
注册了该中间件后,就可以将其附加到路由中。如果传入请求没有有效签名,则中间件将自动返回 403
错误响应:
Route::post('/unsubscribe/{user}', function (Request $request) {
// ...
})->name('unsubscribe')->middleware('signed');