如何让Laravel临时签名路由提交/打开一次后立即过期?
实现Laravel临时签名路由一次性失效
要让生成的临时签名路由在首次访问/提交后立即失效,需要在Laravel自带的签名验证基础上,额外添加已使用标记的校验。以下是两种可行的实现方案:
方案一:使用缓存实现(轻量快捷)
这种方式无需新增数据库表,适合快速实现:
1. 生成带唯一Token的签名路由
生成路由时,额外添加一个唯一随机Token作为参数,确保每个路由实例唯一:
use Illuminate\Support\Str; use Illuminate\Support\Facades\URL; $token = Str::random(32); $myRoute = URL::temporarySignedRoute( 'unsubscribe', now()->addMinutes(30), ['user' => 1, 'token' => $token] );
2. 在路由处理逻辑中校验并标记已使用
在unsubscribe路由对应的控制器方法里,先验证签名有效性,再检查缓存是否存在该Token:
use Illuminate\Support\Facades\Cache; public function unsubscribe(Request $request) { // 验证签名有效性(Laravel会自动处理,也可手动调用) if (!$request->hasValidSignature()) { abort(403, '无效的链接'); } $token = $request->input('token'); $cacheKey = "used_signed_route:{$token}"; // 检查该链接是否已被使用 if (Cache::has($cacheKey)) { abort(403, '该链接已失效'); } // 标记链接为已使用,缓存有效期和路由一致(30分钟) Cache::put($cacheKey, true, now()->addMinutes(30)); // 执行 unsubscribe 业务逻辑 // ... return response('退订成功'); }
方案二:使用数据库记录(持久化,适合需要审计的场景)
如果需要长期记录链接的使用情况,可以用数据库表存储:
1. 创建迁移文件生成记录表
php artisan make:migration create_signed_route_usages_table
编辑迁移文件,添加必要字段:
public function up() { Schema::create('signed_route_usages', function (Blueprint $table) { $table->id(); $table->unsignedInteger('user_id')->nullable(); // 关联用户(可选) $table->string('route_name'); // 路由名称 $table->string('token')->unique(); // 唯一Token $table->timestamp('used_at')->nullable(); // 使用时间 $table->timestamps(); }); } public function down() { Schema::dropIfExists('signed_route_usages'); }
执行迁移:
php artisan migrate
2. 生成带Token的签名路由
和缓存方案一样,生成路由时添加唯一Token,并提前存入数据库标记为未使用:
use Illuminate\Support\Str; use Illuminate\Support\Facades\URL; use App\Models\SignedRouteUsage; $token = Str::random(32); $myRoute = URL::temporarySignedRoute( 'unsubscribe', now()->addMinutes(30), ['user' => 1, 'token' => $token] ); SignedRouteUsage::create([ 'user_id' => 1, 'route_name' => 'unsubscribe', 'token' => $token, ]);
3. 控制器中校验并标记已使用
use App\Models\SignedRouteUsage; public function unsubscribe(Request $request) { if (!$request->hasValidSignature()) { abort(403, '无效的链接'); } $token = $request->input('token'); $routeUsage = SignedRouteUsage::where('token', $token)->first(); if (!$routeUsage || $routeUsage->used_at) { abort(403, '该链接已失效'); } // 标记为已使用 $routeUsage->update(['used_at' => now()]); // 执行退订逻辑 // ... return response('退订成功'); }
注意事项
- 无论哪种方案,都要确保
token参数的唯一性,避免不同用户的路由出现冲突。 - 缓存方案的优势是无需维护数据库,性能更高;数据库方案适合需要追溯链接使用记录的场景。
内容的提问来源于stack exchange,提问作者Gabriel Rogath
相关产品推荐
相关产品推荐

