我尝试使用
Laravel 8.x
和 Laravel sanctum 2.14.2
来验证我的 API 和 UUID 作为我的 User
模型的主键。
我的定制
PersonalAccessToken
模型
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Laravel\Sanctum\PersonalAccessToken as SanctumPersonalAccessToken;
class PersonalAccessToken extends SanctumPersonalAccessToken
{
use HasFactory;
protected $table = 'personal_access_tokens';
public function tokenable()
{
return $this->morphTo('tokenable', "tokenable_type", "tokenable_id", "uuid");
}
}
我的
personal_access_tokens
迁移架构
...
public function up()
{
Schema::dropIfExists('personal_access_tokens');
Schema::create('personal_access_tokens', function (Blueprint $table) {
$table->id();
$table->uuidMorphs('tokenable');
$table->string('name');
$table->string('token', 64)->unique();
$table->text('abilities')->nullable();
$table->timestamp('last_used_at')->nullable();
$table->timestamps();
});
}
...
我的
AppServiceProvider
...
use App\Models\PersonalAccessToken;
use Illuminate\Support\Facades\URL;
use Illuminate\Support\ServiceProvider;
use Laravel\Sanctum\Sanctum;
class AppServiceProvider extends ServiceProvider
{
/**
* Register any application services.
*
* @return void
*/
public function register()
{
Sanctum::ignoreMigrations();
}
/**
* Bootstrap any application services.
*
* @return void
*/
public function boot()
{
if($this->app->environment('production')) {
URL::forceScheme('https');
}
Sanctum::usePersonalAccessTokenModel(PersonalAccessToken::class);
}
}
当我尝试使用
$user->createToken($user->email)->plainTextToken
获取令牌时,出现此错误:
SQLSTATE[23000]: Integrity constraint violation: 1048 Column 'tokenable_id' cannot be null (SQL: insert into `personal_access_tokens` (`name`, `token`, `abilities`, `tokenable_id`, `tokenable_type`, `updated_at`, `created_at`) values ([email protected], 85dbe44c32a999a01f4a97d9c9eab0710125a6ac5f861ab546a5822f61015b23, [\"*\"], ?, App\\Models\\User, 2022-03-20 19:16:43, 2022-03-20 19:16:43))
我认为错误的原因是我使用
uuid
作为用户表中的主键
Schema::create('users', function (Blueprint $table) {
$table->uuid('uuid')->primary();
...
});
更新
我的
User
模特
...
class User extends Authenticatable
{
use HasUUID;
use HasApiTokens;
use HasFactory;
use Notifiable;
use HasRoles;
...
public function tokens()
{
return $this->morphMany(Sanctum::$personalAccessTokenModel, 'tokenable', "tokenable_type", "tokenable_id");
}
...
}
如有任何帮助,我们将不胜感激。
您创建自定义
PersonalAccessToken
模型有什么特殊原因吗?
如果您只想将 UUID 作为
User
模型的主键,则无需创建自定义 PersonalAccessToken
模型即可实现。
您的
personal_access_tokens
迁移模式看起来不错。
我认为错误的原因是我使用 uuid 作为主要 在用户表中键入
Schema::create('users', function (Blueprint $table) { $table->uuid('uuid')->primary(); ... });
这可能是问题所在。尝试将列名从 uuid 更改为 id 并查看是否有效
$table->uuid('id')->primary();
如果您必须使用列名称作为主键的 uuid,请尝试将以下内容添加到您的
User
模型
protected $primaryKey='uuid'
默认情况下,eloquent 假定主键列的名称为
'id'
。这将使 eloquent 知道寻找 'uuid'
作为用户模型的主键列。
此外,由于您没有使用主键的默认整数数据类型,请确保您的
User
模型中有以下内容
public $incrementing=false
protected $keyType='string'
您可以参考 Laravel 文档 主键
抱歉回复晚了。我为遇到与上述相同问题的任何人提供解决方案。 问题出在我的
UUId Traits
。当我们想要创建自己的 Traits 时,我们应该按照 Laravel 的建议使用 boot magic method
。
解决方案:
使用
App\Traits\HasUUID
和正确的代码
<?php
namespace App\Traits;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Str;
trait HasUUID
{
/**
* Boot functions from Laravel.
*/
// protected static function boot() <- This line is INCORRECT
protected static function bootHasUUID()
{
static::creating(function (Model $model) {
$model->primaryKey = 'uuid';
$model->keyType = 'string'; // In Laravel 6.0+ make sure to also set $keyType
$model->incrementing = false;
if (empty($model->{$model->getKeyName()})) {
$model->{$model->getKeyName()} = Str::uuid()->toString();
}
});
}
/**
* Get the value indicating whether the IDs are incrementing.
*
* @return bool
*/
public function getIncrementing()
{
return false;
}
/**
* Get the auto-incrementing key type.
*
* @return string
*/
public function getKeyType()
{
return 'string';
}
}
最后,在
App\Traits\HasUUID
模型中添加 User
。
...
use App\Traits\HasUUID;
...
class User extends Authenticatable
{
use HasUUID;
...
}
无需定制
Sanctum's Model
。非常感谢@Hussain,@Dharman
要在用户迁移中实现 UUID,请使用以下代码:
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('users', function (Blueprint $table) {
$table->uuid('id')->primary();
// Anothers columns
});
}
对于您的personal_access_tokens 迁移,请使用以下内容:
public function up(): void
{
Schema::create('personal_access_tokens', function (Blueprint $table) {
$table->id();
// $table->morphs('tokenable'); Remove this line
$table->string('tokenable_type'); // Add this line
$table->uuid('tokenable_id'); // Add this line
$table->string('name');
$table->string('token', 64)->unique();
$table->text('abilities')->nullable();
$table->timestamp('last_used_at')->nullable();
$table->timestamp('expires_at')->nullable();
$table->timestamps();
});
}
通过执行此操作,系统将识别 tokenable_id 列的类型为 UUID。
此外,不要忘记在您的 Users 模型中包含 HasUuids 特征:
class Users extends Model
{ 使用 HasFactory、SoftDeletes、Notific、HasApiTokens、HasUuids;
/**
* The attributes that are mass assignable.
*
* @var array<int, string>
*/
protected $fillable = [
'name',
'document',
'email',
'password',
'role',
];
// ANOTHER FUNCTION/PROTECTED
希望对你有帮助