Laravel URL 处理:URL 签名 1 个改进

问题

我如何防止公开 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');

参考

本文为 Wiki 文章,邀您参与纠错、纰漏和优化
讨论数量: 0
(= ̄ω ̄=)··· 暂无内容!

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!