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

Laravel 11 Passport客户端凭证授权:不同机器的Scope配置与验证问题

解决Laravel Passport M2M客户端绑定固定Scope的问题

要给每个M2M客户端绑定固定Scope,防止它们通过scope=*获取全量权限,你需要扩展Laravel Passport的客户端凭证授权逻辑,具体步骤如下:

1. 给客户端表添加允许的Scope字段

首先创建迁移,为oauth_clients表新增存储允许Scope的字段:

php artisan make:migration add_allowed_scopes_to_oauth_clients_table --table=oauth_clients

打开生成的迁移文件,修改up方法:

public function up(): void
{
    Schema::table('oauth_clients', function (Blueprint $table) {
        $table->json('allowed_scopes')->nullable();
    });
}

执行迁移:

php artisan migrate

2. 为客户端配置固定Scope

直接在数据库中修改oauth_clients表的allowed_scopes字段:

  • 负责发送数据的客户端:填入["can-send"]
  • 负责读取数据的客户端:填入["can-read"]

3. 自定义客户端凭证授权处理器

创建自定义控制器替换Passport默认的客户端凭证授权逻辑,强制使用客户端绑定的Scope:

<?php

namespace App\Passport;

use Laravel\Passport\Http\Controllers\ClientCredentialsController;
use Psr\Http\Message\ServerRequestInterface;

class CustomClientCredentialsController extends ClientCredentialsController
{
    public function issueToken(ServerRequestInterface $request)
    {
        // 验证并获取当前请求的客户端实例
        $client = $this->server->validateAuthenticatedClient($request);
        
        // 强制使用客户端预配置的Scope,忽略请求中的scope参数
        $scopes = $client->allowed_scopes ?? [];
        
        // 生成带固定Scope的访问令牌
        $token = $this->server->createToken(
            $client,
            $scopes,
            []
        );
        
        return response()->json($token->convertToResponseBody());
    }
}

4. 替换Passport默认路由

在App\Providers\AuthServiceProvider的boot方法中,替换默认的客户端凭证授权路由:

use App\Passport\CustomClientCredentialsController;
use Laravel\Passport\Passport;

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

    Passport::routes(function ($router) {
        // 保留其他默认路由
        $router->forAccessTokens();
        $router->forTransientTokens();
        $router->forPasswordReset();
        
        // 替换客户端凭证授权路由为自定义控制器
        $router->post('/token', [CustomClientCredentialsController::class, 'issueToken']);
    });

    // 保留原有的Scope定义
    Passport::tokensCan([
        'can-send' => 'Can send data',
        'can-read' => 'Can read data',
    ]);
}

5. 可选:添加Scope校验中间件(额外安全保障)

如果需要进一步校验令牌Scope是否符合客户端权限,可自定义中间件:

php artisan make:middleware ValidateClientScopes

打开中间件文件:

<?php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;
use Laravel\Passport\Token;
use Symfony\Component\HttpFoundation\Response;

class ValidateClientScopes
{
    public function handle(Request $request, Closure $next): Response
    {
        $tokenId = $request->bearerToken() ? explode('|', $request->bearerToken())[0] : null;
        if (!$tokenId) {
            return response()->json(['error' => 'Unauthorized'], 401);
        }

        $token = Token::find($tokenId);
        if (!$token) {
            return response()->json(['error' => 'Invalid token'], 401);
        }

        $clientAllowedScopes = $token->client->allowed_scopes ?? [];
        $tokenScopes = $token->scopes;

        // 校验令牌的所有Scope都在客户端允许范围内
        foreach ($tokenScopes as $scope) {
            if (!in_array($scope, $clientAllowedScopes)) {
                return response()->json(['error' => 'Scope not allowed for this client'], 403);
            }
        }

        return $next($request);
    }
}

在app/Http/Kernel.php中注册中间件:

protected $routeMiddleware = [
    // ... 其他中间件
    'client.scopes' => \App\Http\Middleware\ValidateClientScopes::class,
];

最后给路由加上该中间件:

Route::get('/send', function (Request $request) {
    return 'You can send data';
})->middleware(['client:can-send', 'client.scopes']);

Route::get('/read', function (Request $request) {
    return 'You can read data';
})->middleware(['client:can-read', 'client.scopes']);

完成以上配置后,无论客户端请求令牌时传入什么scope参数,都会被强制替换为该客户端预配置的固定Scope,彻底解决scope=*获取全量权限的问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 06:17:10