【问题标题】:Why first-party clients can't handle 'authorization_code' grant type on Laravel Passport为什么第一方客户端无法处理 Laravel Passport 上的“authorization_code”授权类型
【发布时间】:2021-06-04 00:16:07
【问题描述】:

我正在使用两个应用程序:accounts.domain.com(Laravel 应用程序)和dash.domain.com(不是 laravel,而是 php)。我希望dash 用户通过accounts 登录以使用该应用程序,所以我想我可以使用 OAuth 来实现这一点。

我安装了 Laravel Passport,在获得授权码时一切正常:

$query = http_build_query([
    'client_id' => $clientId,
    'redirect_uri' => $redirectUri,
    'response_type' => 'code',
    'scope' => '*',
    'state' => $state,
]);

return redirect('https://accounts.domain.com/oauth/authorize?'.$query);

但后来我尝试获取访问令牌:

$response = $http->post('https://accounts.domain.com/oauth/token', [
    'form_params' => [
        'grant_type' => 'authorization_code',
        'client_id' => $clientId,
        'client_secret' => $clientSecret,
        'redirect_uri' => $redirectUri,
        'code' => $code,
    ],
]);

我得到了这个错误:

{
    "error": "invalid_client",
    "error_description": "Client authentication failed",
    "message": "Client authentication failed"
}

所以我用谷歌搜索了这个错误,我发现我的凭据可能有错误,所以我检查了它们,尝试重新创建它们,但什么也没有。

最后我找到了这个文件vendor/laravel/passport/src/Bridge/ClientRepository.php,我发现在用于验证客户端的handlesGrant 方法中有一些非常有趣的东西:

protected function handlesGrant($record, $grantType)
{
    // ...

    switch ($grantType) {
        case 'authorization_code':
            return ! $record->firstParty();
        // ...
        default:
            return true;
    }
}

我改变了这一行

return ! $record->firstParty();

到这里:

return $record->firstParty();

一切正常。所以,我可以看到,使用'grant_type' => 'authorization_code' 仅对第三方客户端有效。

我的问题是:¿为什么第一方客户不能使用 'authorization_code' 作为授权类型?如果可以,¿如何在不更改 Laravel Passport 文件的情况下实现这一点?

【问题讨论】:

  • 第一方是指资源所有者?一个需要凭据,另一个不需要。
  • 我猜你没看错@adam,尽管 Laravel Passport 确实允许你为 firstParty 客户端实现你的逻辑。我将我的客户设置为 firstParty 以关闭批准屏幕,因为我真的不希望当用户从我自己的应用程序登录时出现这种情况。这完全独立于创建公共和私人应用程序客户端,所以我想我也觉得这方面的逻辑如此严格也很奇怪。

标签: laravel oauth-2.0 laravel-passport


【解决方案1】:

我偶然发现了同样的问题,不知道为什么这是默认行为。您可以轻松扩展 ClientRepository 并将其重新绑定到服务容器:

  1. 创建文件app\Passport\ClientRepository.php 并放入以下内容:
<?php

namespace App\Passport;

use Laravel\Passport\Bridge\ClientRepository as BaseClientRepository;

class ClientRepository extends BaseClientRepository
{
    /**
     * Determine if the given client can handle the given grant type.
     *
     * @param  \Laravel\Passport\Client  $record
     * @param  string  $grantType
     * @return bool
     */
    protected function handlesGrant($record, $grantType)
    {
        if (is_array($record->grant_types) && ! in_array($grantType, $record->grant_types)) {
            return false;
        }

        switch ($grantType) {
            case 'personal_access':
                return $record->personal_access_client && $record->confidential();
            case 'password':
                return $record->password_client;
            case 'client_credentials':
                return $record->confidential();
            default:
                return true;
        }
    }
}
  1. 注册您的 ClientRepository,将其重新绑定到服务容器:
<?php

namespace App\Providers;

use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
use App\Passport\ClientRepository;

class AuthServiceProvider extends ServiceProvider
{
    // Other code

    /**
     * Register any application services.
     *
     * @return void
     */
    public function register()
    {
        $this->bindClientRepository();
    }

    /**
     * Register the client repository.
     *
     * @return void
     */
    protected function bindClientRepository()
    {
        $this->app->bind(\Laravel\Passport\Bridge\ClientRepository::class, ClientRepository::class);
    }
}

【讨论】:

  • 感谢您的建议,我会尝试这种方法。
  • 谢谢你,为我解决了这个问题。
猜你喜欢
  • 2020-08-06
  • 1970-01-01
  • 2018-12-11
  • 2019-01-24
  • 2021-12-21
  • 1970-01-01
  • 2015-02-20
  • 1970-01-01
  • 2017-05-14
相关资源
最近更新 更多