用户模型中带有 uuid 列的 Laravel Sanctum 不保存 tokenable_id

问题描述 投票:0回答:3

我尝试使用

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");
    }
    
    ...
}

如有任何帮助,我们将不胜感激。

php laravel laravel-sanctum sanctum
3个回答
3
投票

您创建自定义

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 文档 主键


2
投票

抱歉回复晚了。我为遇到与上述相同问题的任何人提供解决方案。 问题出在我的

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


0
投票

要在用户迁移中实现 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

希望对你有帮助

© www.soinside.com 2019 - 2024. All rights reserved.