【问题标题】:Laravel Passport invalid scope(s) provided exceptionLaravel Passport 无效范围提供了异常
【发布时间】:2020-03-08 09:23:23
【问题描述】:
  • Laravel Passport 8.0.0 版
  • Laravel 版本:6.2

我在AuthServiceProvider.php 文件的引导方法中使用Passport::tokensCan 方法定义了我的API 的范围:

Passport::routes();

Passport::tokensCan([
    'view-posts' => 'View posts',
    'create-posts' => 'Create posts'
]);

app/Http/Kernel.php 文件的$routeMiddleware 属性中添加了以下中间件:

protected $routeMiddleware = [
    'auth' => \App\Http\Middleware\Authenticate::class,
    'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
    /*
    . . .
    */
    'scopes' => \Laravel\Passport\Http\Middleware\CheckScopes::class,
    'scope' => \Laravel\Passport\Http\Middleware\CheckForAnyScope::class,
];

然后,我在routes/api.php 中保护了一个API 路由:

Route::post('/posts', [
    'uses' => 'PostController@store',
    'middleware' => ['auth:api', 'scope:create-posts']
]);

在客户端应用中,我的授权路线是 (routes/web.php):

Route::middleware(['auth'])->group(function () {
    Route::get('/auth/blogger', 'BloggerAuthController@redirect');
    Route::get('/auth/blogger/callback', 'BloggerAuthController@callback');
});

BloggerAuthController控制器是这样的:

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use GuzzleHttp\Client as Guzzle;

class BloggerAuthController extends Controller
{
    protected $client;

    public function __construct(Guzzle $client)
    {
        $this->client = $client;
    }

    public function redirect()
    {
        $query = http_build_query([
            'client_id' => '3',
            'redirect_uri' => 'http://localhost:8001/auth/blogger/callback',
            'response_type' => 'code',
            'scope' => 'view-posts'
        ]);

        return redirect('http://localhost:8000/oauth/authorize?' . $query);
    }

    public function callback(Request $request)
    {
        $response = $this->client->post('http://localhost:8000/oauth/token', [
            'form_params' => [
                'grant_type' => 'authorization_code',
                'client_id' => '3',
                'client_secret' => 'gG5HcVn1JlGhzO0RfgTfWuqP8IVro1Qhu9g2q0Dq',
                'redirect_uri' => 'http://localhost:8001/auth/blogger/callback',
                'code' => $request->code
            ]
        ]);

        $response = json_decode($response->getBody());

        $request->user()->token()->delete();

        $request->user()->token()->create([
            'access_token' => $response->access_token
        ]);

        return redirect('/home');
    }
}

当我 (POST) 从我的客户端应用程序向 /api/posts 请求时, 我得到一个例外:

{
    "message": "Invalid scope(s) provided.",
    "exception": "Symfony\\Component\\HttpKernel\\Exception\\AccessDeniedHttpException",
    "file": "C:\\Users\\nbayramberdiyev\\Desktop\\fresh\\vendor\\laravel\\framework\\src\\Illuminate\\Foundation\\Exceptions\\Handler.php",
    "line": 206,
    /*
    . . .
    */
}

但预期的结果是:

{
    "message": "Unauthenticated."
}

状态为 401。

为什么会这样?我错过了docs 中的任何内容吗?

【问题讨论】:

  • 你找到解决办法了吗?

标签: laravel oauth laravel-passport laravel-6


【解决方案1】:

你只需要覆盖 MissingScopeException 异常来返回你想要的任何消息,并且仍然在你的路由文件中作用域中间件

在渲染函数的Handler文件中的Exception文件夹中

if ($exception instanceof MissingScopeException && $request->wantsJson()){
            return response()->json([
                'error' => 'Unauthenticated',
            ], 403);
        }

【讨论】:

    【解决方案2】:

    您请求view-posts 范围,但随后尝试创建需要create-posts 范围的帖子。这就是问题所在。

    【讨论】:

    • 是的,完全正确。但在我的情况下,它应该返回带有消息 Unauthenticated. 的 401 响应,而不是抛出异常。
    【解决方案3】:

    创建access_token时,添加范围:create-posts

     $request->user()->token()->create([
                'access_token' => $response->access_token
            ], ['create-posts']);
    
    

    【讨论】:

      【解决方案4】:

      我通过添加中间件和验证范围来解决这个问题,而不是在路由中使用 'scopes:some_scope'。这是我的解决方法。

      1. 创建一个中间件并在这样的中间件中验证范围。

        public function handle($request, Closure $next){
        if (!$request->user()->tokenCan('user')) {
            return response()->json([
                'message' => "Unauthenticated",
            ]);
        }
        
        return $next($request);
        

        }

      2. request-&gt;user()-&gt;tokenCan('user') 验证范围。

      3. 你可以返回任何你想要的错误信息。

        return response()->json([
            'message' => "Unauthenticated",
        ]);
        
      4. 使用中间件。我一直在寻找那个答案,这是我能想到的最好的解决方案,它仍然处于边界并且没有太多的工作。如果您确实解决了更好的方法,请也分享给我。我也想知道。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-01-31
        • 2021-03-29
        • 1970-01-01
        • 2023-02-01
        • 1970-01-01
        • 2015-09-25
        • 2020-06-06
        • 2011-05-31
        相关资源
        最近更新 更多