Jak dodać role i uprawnienia do zalogowanego użytkownika z Sanctum w Laravel.
W sanctum ładujesz relacje za pomocą ->fresh(['roles','permissions']) dla zalogowanego użytkownika.
<?php
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Route;
Route::name('api.')->group(function () {
// All logged
Route::middleware(['auth:sanctum'])->group(function () {
// User
Route::get('/user', function (Request $request) {
// Return model with relations and attributes
return Auth::user()->fresh(['roles', 'permissions'])->toArray();
})->name('user');
});
});
Lub w modelu użytkownika dodajesz attrybut permission przez $appends co zaczyta automatycznie relacje roles, i permissions.
<?php
namespace App\Models;
// use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Laravel\Sanctum\HasApiTokens;
use Spatie\Permission\Traits\HasRoles;
class User extends Authenticatable
{
/** @use HasFactory<\Database\Factories\UserFactory> */
use HasFactory, Notifiable;
use HasApiTokens;
use HasRoles;
/**
* Default guard name
*
* @var string
*/
protected $guard = 'web';
/**
* Display relations with model
*
* @var array
*/
// protected $with = ['roles', 'permissions'];
/**
* Display relations with model (appends roles and permissions with sanctum logged user)
*
* @var array
*/
protected $appends = ['permission'];
/**
* The attributes that are mass assignable.
*
* @var list<string>
*/
protected $fillable = [
'name',
'email',
'password',
];
/**
* The attributes that should be hidden for serialization.
*
* @var list<string>
*/
protected $hidden = [
'password',
'remember_token',
];
/**
* Get the attributes that should be cast.
*
* @return array<string, string>
*/
protected function casts(): array
{
return [
'password' => 'hashed',
'email_verified_at' => 'datetime:Y-m-d H:i:s',
'created_at' => 'datetime:Y-m-d H:i:s',
'updated_at' => 'datetime:Y-m-d H:i:s',
'deleted_at' => 'datetime:Y-m-d H:i:s',
];
}
/**
* Default guard name permissions
*
* @var string
*/
protected function getDefaultGuardName()
{
return $this->guard;
}
/**
* Get all permissions (from roles and direct)
*
* @var string
*/
protected function getPermissionAttribute()
{
return $this->getAllPermissions();
}
}
<?php
namespace Tests\Feature;
use App\Enums\Spatie\RolesEnum;
use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Laravel\Sanctum\Sanctum;
use Spatie\Permission\Models\Permission;
use Spatie\Permission\Models\Role;
use Tests\TestCase;
class SanctumTest extends TestCase
{
use RefreshDatabase;
/**
* Logged user details
*
* @return void
*/
public function test_api_user_only_logged(): void
{
$this->seed();
$user = User::factory()->create();
$role = app(Role::class)->findOrCreate('admin', 'web');
$user->assignRole($role);
$permission = app(Permission::class)->findOrCreate('user_view', 'web');
$user->givePermissionTo($permission);
Sanctum::actingAs($user, ['*'], 'web');
$response = $this->get('/api/user');
$response->assertOk();
$response->assertJsonStructure([
"roles",
"permissions",
// "permission", // Only with appends
]);
// Show in console
// dd($response->decodeResponseJson());
}
}
/**
* Sanctum expired token middleware.
*
* Add middleware in bootstrap/app.php
* $middleware->api(prepend: [ \App\Http\Middleware\Api\ExpiredToken::class ]);
*/
class ExpiredToken
{
public function handle(Request $request, Closure $next)
{
$bearer = $request->bearerToken();
if ($bearer) {
$token = PersonalAccessToken::findToken($bearer);
if ($token instanceof PersonalAccessToken) {
if($token->expires_at && $token->expires_at->isPast()) {
$request->merge([
'token_expired' => $token->expires_at && $token->expires_at->isPast(),
'token_details' => $token
]);
return response()->json([
'message' => 'Expired Token.',
'token_expired' => $token->expires_at && $token->expires_at->isPast(),
'token_details' => $token
], 403);
}
}
}
return $next($request);
}
}