[Laravel 教程] Model 保留 ID 的情况下对外提供 UUID
在某些应用程序中,不暴露 ID 可以避免别人轻易获悉你数据库里模型的数量。
译者注:隐藏 ID 也可有效防止用户恶意遍历网站的内容。
嘿, 想象一下,在我的 Podcast 应用程序中,我设置了一个默认 id 在 Laravel 的 Podcast 模型中,它是一个整数,每次插入一行时都会自动增加一个,因此表中的第47个 Podcast 的 id 为47。 然后我在我的网站内声称:“这个 Podcast 应用程序拥有数百万个播客,所以千万不要错过!”,在看到最新播客 ID 时很容易被揭穿:
https://podcast.app/podcasts/47
在不需要重新连接应用程序中的所有内容的情况下隐藏ID,并且希望不被识破? 好的,有一种方法。
设置数据库
有些数据库可以配置为在插入新行时将 UUID 设置为主键。你应该在正在使用的 RDBMS 上检查这一点,因为每个 RDBMS 的实现都有所不同。
你还可以告诉应用程序在使用 创建 Eloqument 事件新纪录时设置默认 UUID ,但这将使你在任何情况下都得使用 Eloqument 。如果你直接向数据库中插入一条记录,你可能会得到一个错误——这也是我喜欢在数据库中设置自动 UUID 而不是应用程序的原因之一,它不应该依赖于任何东西,因为这是数据库行为。
总之,你应该像这样使用 Laravel 设置你的数据库:
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreatePodcastTable extends Migration
{
/**
* 运行数据库迁移
*
* @return void
*/
public function up()
{
Schema::create('podcast', function (Blueprint $table) {
$table->bigIncrements('id');
$table->uuid('uuid')->index();
$table->string('filename');
$table->string('path');
$table->string('service');
$table->string('format', 4);
$table->unsginedTinyInteger('quality', 4);
$table->timestamps();
$table->timestamps();
$table->softDeletes();
});
}
/**
* 回滚数据库迁移
*
* @return void
*/
public function down()
{
Schema::dropIfExists('podcast');
}
}
正如你看到的,我们增加了 $table->uuid('uuid')->index()
。这段代码告诉 Laravel 去使用 UUID 这一列(如果支持,或者使用字符串列),并在这一列上创建一个索引,这样就可以通过 UUID 快速检索行,就像有人访问这个 URL 时所做的那样:
https://podcast.app/podcast/535c4cdf-70a0-4615-82f2-443e95c86aec
你可能会争辩说 另外一个索引会妨碍插入操作,但是这是一个权衡。
现在,问题在于控制器和模型。
将模型连接至 UUID
你不需要在模型中做任何事,除了两件事:将 ID 从序列化中隐藏,并允许模型使用 UUID 进行「 URL 路由」。
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Podcast extends Model
{
/**
* 数组中隐藏的属性
*
* @var array
*/
protected $hidden = [
'id'
];
/**
* 获取模型的路由键
*
* @return string
*/
public function getRouteKeyName()
{
return 'uuid';
}
// ……其余的模型代码
}
要隐藏 ID ,我们可以将 id
列添加至隐藏属性数组中。当模型被序列化时,比如转换为数组或 JSON 字符串时,将不会显示 ID 。当然,你也可以像访问属性或者数组键那样访问获得的属性的 ID。
下一步则告诉 Laravel ,当 URL 包含模型的 UUID 时,则通过 uuid
列获取模型。这将允许通过设置一个路由来查找模型,例如:
Route::get({podcast}, 'PodcastController@show');
然后在我们的 PodcastController
类中使用它。
/**
* 通过 UUID 显示播客
*
* @param \App\Podcast $podcast
* @return \Illuminate\Http\Response
/*
public function show(Podcast $podcast)
{
return response()->view('response', [
'podcast' => $podcast
]);
}
你也可以使用模型中的 resolveRouteBinding() 方法,你是否可以以编程的方式设置如何通过给定值来检索模型。你甚至可以允许经过身份验证的管理员根据记录的 ID 或者 UUID 来获取记录。
就这样,没什么可做的了。该技术还允许在 应用程序生成后 设置 UUID 。
本文中的所有译文仅用于学习和交流目的,转载请务必注明文章译者、出处、和本文链接
我们的翻译工作遵照 CC 协议,如果我们的工作有侵犯到您的权益,请及时联系我们。
迁移脚本为什么有两个 service?
$table->string('service');
文章上没有看到生成 uuid 的动作,在 mysql 情况下,上面这个迁移并不会自动生成 uuid,所以还需要在 Model 中新建数据事件处理
@陈伯乐
@Olivia-outshine 感谢回复,我写了一个 trait
https://gist.github.com/bolechen/ca98c08ba...
那么id字段有什么用?为何不直接吧id 设置成UUID?
只能用模型注入才能查询到数据么。如果不用模型注入是不是不行