You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于用户角色为Laravel Passport添加Scopes的技术问询

How to Add Role-Based Scopes to Laravel Passport with Laravel-permission

Hey there! I get that building a secure SPA API from scratch can feel a bit overwhelming, especially when combining Passport and Laravel-permission for the first time. Let’s break this down into clear, actionable steps to tie user roles directly to Passport scopes.

1. Ensure Your Core Packages Are Set Up First

Before diving into scopes, make sure both Laravel Passport and Laravel-permission are properly installed and configured:

  • Install Passport:
    composer require laravel/passport
    php artisan migrate
    php artisan passport:install
    
  • Install Laravel-permission:
    composer require spatie/laravel-permission
    php artisan vendor:publish --provider="Spatie\Permission\PermissionServiceProvider"
    php artisan migrate
    

Don’t forget to add the HasApiTokens trait to your User model, plus the HasRoles trait from Laravel-permission to enable role management.

2. Define Your Passport Scopes

Scopes are the granular permissions your API will enforce (e.g., view-users, manage-posts). Register them in your AuthServiceProvider’s boot method:

use Laravel\Passport\Passport;

public function boot()
{
    $this->registerPolicies();

    Passport::routes();

    // Define your scopes with descriptive labels
    Passport::scope('view-users', 'View all user profiles')
        ->scope('manage-users', 'Create, edit, and delete users')
        ->scope('manage-posts', 'Create, edit, and delete blog posts');
}

If you haven’t already, run php artisan passport:client --personal to create a personal access client for your SPA.

Laravel-permission’s roles don’t come with a built-in link to Passport scopes, so we’ll create a pivot table to connect them:

  • Generate the pivot table migration:
    php artisan make:migration create_role_scope_table
    
  • Update the migration file to link roles to Passport’s oauth_scopes table:
    public function up()
    {
        Schema::create('role_scope', function (Blueprint $table) {
            $table->foreignId('role_id')->constrained()->onDelete('cascade');
            $table->foreignId('scope_id')->constrained('oauth_scopes')->onDelete('cascade');
            $table->primary(['role_id', 'scope_id']);
        });
    }
    
  • Run the migration: php artisan migrate

4. Add Relationship to Your Role Model

Open your Role model (from Laravel-permission) and add a relationship to Passport’s Scope model:

use Laravel\Passport\Scope;

class Role extends \Spatie\Permission\Models\Role
{
    public function scopes()
    {
        return $this->belongsToMany(Scope::class, 'role_scope');
    }
}

5. Assign Scopes to Roles

Now you can assign scopes to roles—this can be done via seeders, a backend admin panel, or even Tinker for quick testing:

// Example: Assign full access scopes to an Admin role
$adminRole = Role::findByName('admin');
$manageUsersScope = Scope::find('manage-users');
$managePostsScope = Scope::find('manage-posts');

$adminRole->scopes()->attach([$manageUsersScope->id, $managePostsScope->id]);

// Example: Assign limited scopes to an Editor role
$editorRole = Role::findByName('editor');
$viewUsersScope = Scope::find('view-users');
$managePostsScope = Scope::find('manage-posts');

$editorRole->scopes()->attach([$viewUsersScope->id, $managePostsScope->id]);

6. Attach Role Scopes When Issuing Access Tokens

When a user logs in and requests an access token, we need to automatically include all scopes associated with their roles. Update your login controller (or wherever you generate tokens) to do this:

public function login(Request $request)
{
    $credentials = $request->validate([
        'email' => 'required|email',
        'password' => 'required',
    ]);

    if (!Auth::attempt($credentials)) {
        return response()->json(['message' => 'Invalid credentials'], 401);
    }

    $user = Auth::user();
    // Fetch all unique scopes from the user's assigned roles
    $scopes = $user->roles->flatMap(function ($role) {
        return $role->scopes->pluck('id')->toArray();
    })->unique();

    // Create token with the merged scopes
    $token = $user->createToken('SPA Access Token', $scopes)->accessToken;

    return response()->json(['access_token' => $token]);
}

7. Protect Your API Routes with Scopes

Finally, use Passport’s scope middleware to protect your API endpoints. Only users with the required scope (via their role) will be able to access them:

use Illuminate\Support\Facades\Route;

Route::middleware('auth:api')->group(function () {
    // Only users with 'view-users' scope can access this
    Route::get('/users', [UserController::class, 'index'])->middleware('scope:view-users');
    
    // Only users with 'manage-users' scope can access this
    Route::post('/users', [UserController::class, 'store'])->middleware('scope:manage-users');
    
    // Only users with 'manage-posts' scope can access these post routes
    Route::resource('/posts', PostController::class)->except(['create', 'edit'])->middleware('scope:manage-posts');
});

Bonus: Combine with Role Middleware (Optional)

For extra security, you can stack Laravel-permission’s role middleware alongside Passport’s scope middleware to enforce both role and scope checks:

Route::post('/users', [UserController::class, 'store'])
    ->middleware(['auth:api', 'role:admin', 'scope:manage-users']);

This setup ensures your API endpoints are only accessible to users with the right roles and corresponding scopes—no more unprotected routes!

内容的提问来源于stack exchange,提问作者Zero

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 08:55:38