Skip to content

Using UUID/GUID for primary key on user table #489

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
benyanke opened this issue Oct 5, 2017 · 14 comments · Fixed by #2089
Closed

Using UUID/GUID for primary key on user table #489

benyanke opened this issue Oct 5, 2017 · 14 comments · Fixed by #2089

Comments

@benyanke
Copy link
Contributor

benyanke commented Oct 5, 2017

Not sure where to put this, but I am successfully using this using my UUID user IDs, in place of the integer IDs. Just wanted to document it publicly in case anyone else tries to do this.

I accomplished this by replacing every instance of $table->morphs('model') with:

$table->uuid('model_id');
$table->string('model_type');

I am using GUIDs because my main authentication is linked with Active Directory (via Adldap2/Adldap2-Laravel), and I need to use the AD primary keys as my primary keys to ensure user relation integrity to active directory.

@AlexVanderbist
Copy link
Member

Glad you got it working without any issues! Thanks for letting us know.

@ctf0
Copy link
Contributor

ctf0 commented Jan 21, 2018

@AlexVanderbist can u add this to the docs ?

@AlexVanderbist
Copy link
Member

@ctf0 good call, added a note here: a435278

@addingama
Copy link

I think there is something missing on the doc.

We need to update user model too.

class User extends Authenticatable
{
    ....

   // Add this 3 lines to override laravel default setting
    protected $primaryKey = 'id';
    public $incrementing = false;
    protected $keyType = 'string';

    ...
}

@dariuszjastrzebski
Copy link

@dashracer in my case it doesn't work with $incrementing = false . Only $keyType resolved the issue. Are you sure that $incrementing should be set to false according to UUID?

@benyanke
Copy link
Contributor Author

This is what I had to do in the top of my user model to make it work:

    public $incrementing = false;
    protected $primaryKey = 'guid';

@dariuszjastrzebski
Copy link

@benyanke it's weird. Can you look at my issue: #824 ?

@miguelsmuller
Copy link

I have the same problem and I do not know how to solve ...
when I run assignRole it saves on db but generates an error...

Captura de Tela (3)
Captura de Tela (4)

@drbyte
Copy link
Collaborator

drbyte commented May 9, 2019

when I run assignRole it saves on db but generates an error...

@miguelsmuller can you share your config/permission.php file contents?

@markandrewkato
Copy link

markandrewkato commented Aug 19, 2019

@drbyte Hi, I'm having the same problem as @miguelsmuller when using assignRole. I'm using UUID as primary key. Here's my config/permission.php:

<?php

return [

    'models' => [

        /*
         * When using the "HasPermissions" trait from this package, we need to know which
         * Eloquent model should be used to retrieve your permissions. Of course, it
         * is often just the "Permission" model but you may use whatever you like.
         *
         * The model you want to use as a Permission model needs to implement the
         * `Spatie\Permission\Contracts\Permission` contract.
         */

        //'permission' => Spatie\Permission\Models\Permission::class,
        'permission' => \App\Models\Permission::class,

        /*
         * When using the "HasRoles" trait from this package, we need to know which
         * Eloquent model should be used to retrieve your roles. Of course, it
         * is often just the "Role" model but you may use whatever you like.
         *
         * The model you want to use as a Role model needs to implement the
         * `Spatie\Permission\Contracts\Role` contract.
         */

        //'role' => Spatie\Permission\Models\Role::class,
        'role' => \App\Models\Role::class

    ],

    'table_names' => [

        /*
         * When using the "HasRoles" trait from this package, we need to know which
         * table should be used to retrieve your roles. We have chosen a basic
         * default value but you may easily change it to any table you like.
         */

        'roles' => 'roles',

        /*
         * When using the "HasPermissions" trait from this package, we need to know which
         * table should be used to retrieve your permissions. We have chosen a basic
         * default value but you may easily change it to any table you like.
         */

        'permissions' => 'permissions',

        /*
         * When using the "HasPermissions" trait from this package, we need to know which
         * table should be used to retrieve your models permissions. We have chosen a
         * basic default value but you may easily change it to any table you like.
         */

        'model_has_permissions' => 'model_has_permissions',

        /*
         * When using the "HasRoles" trait from this package, we need to know which
         * table should be used to retrieve your models roles. We have chosen a
         * basic default value but you may easily change it to any table you like.
         */

        'model_has_roles' => 'model_has_roles',

        /*
         * When using the "HasRoles" trait from this package, we need to know which
         * table should be used to retrieve your roles permissions. We have chosen a
         * basic default value but you may easily change it to any table you like.
         */

        'role_has_permissions' => 'role_has_permissions',
    ],

    'column_names' => [

        /*
         * Change this if you want to name the related model primary key other than
         * `model_id`.
         *
         * For example, this would be nice if your primary keys are all UUIDs. In
         * that case, name this `model_uuid`.
         */

        'model_morph_key' => 'model_id',
    ],

    /*
     * When set to true, the required permission/role names are added to the exception
     * message. This could be considered an information leak in some contexts, so
     * the default setting is false here for optimum safety.
     */

    'display_permission_in_exception' => false,

    'cache' => [

        /*
         * By default all permissions are cached for 24 hours to speed up performance.
         * When permissions or roles are updated the cache is flushed automatically.
         */

        'expiration_time' => \DateInterval::createFromDateString('24 hours'),

        /*
         * The cache key used to store all permissions.
         */

        'key' => 'spatie.permission.cache',

        /*
         * When checking for a permission against a model by passing a Permission
         * instance to the check, this key determines what attribute on the
         * Permissions model is used to cache against.
         *
         * Ideally, this should match your preferred way of checking permissions, eg:
         * `$user->can('view-posts')` would be 'name'.
         */

        'model_key' => 'name',

        /*
         * You may optionally indicate a specific cache driver to use for permission and
         * role caching using any of the `store` drivers listed in the cache.php config
         * file. Using 'default' here means to use the `default` set in cache.php.
         */

        'store' => 'default',
    ],
];

Edit: I traced the code and the error happens on $model->load('roles') of HasRoles trait, line number 121.

        if ($model->exists) {
            $this->roles()->sync($roles, false);
            $model->load('roles');
        } else {
            $class = \get_class($model);

I tried to comment that line and no errors show when doing assignRole. I tried doing $user->load('roles'); inside php artisan tinker and it shows no error.

Also, I'm only getting the error inside my seeder. On tinker, when I do assignRole, no error occurs.

Last test is I added $user->refresh(); before assignRole and it did the trick.

Any ideas why is this happening?

@RJaydeveloper
Copy link

Was any able to resolve this issue? I am experiencing the same thing as @miguelsmuller

I have tried $user->refresh(); with no luck. The error also gets thrown when I user $user->syncRoles.

Note that this error only occurs when I call I am call a new instance of User (creating a new user) I am able to update the users role with no issues.

@AugmentBLU
Copy link

Same issue as the last 2 people.

I'm having to comment out $model->load() in both the HasPermissions and HasRoles traits.

I replicated the 2 traits and called them within my User model, does anyone think this will cause issues other than making sure that I keep them up to date with any changes?

@drbyte
Copy link
Collaborator

drbyte commented Feb 14, 2020

Can you explain what error is being thrown when $model->load() is called?

Understanding what the error is, and then digging into why that specific error is occurring, will lead to a better outcome.

@gtrig
Copy link

gtrig commented Feb 6, 2021

All you have to do is cast uuid as string. It will solve all your problems.
for example if you create a user like this then do:

$u = User::create([
      'id'             => (string)Str::uuid(),
      'name'           => 'Admin',
      'email'          => 'admin@example.com',
      'password'       => bcrypt('admin'),
      'remember_token' => Str::random(60)
  ]);

  $u->assignRole('Admin');

The problem comes for Str::uuid() that creates an object instead of a string.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.