Laravel Passport 密码授予 - 客户端身份验证失败

Laravel Passport Password Grant - Client authentication failed

听到很多关于 laravel passport 的消息后,我考虑将其实施到我的新项目中,我的要求是创建一个 API 将在移动应用程序中使用。

所以我的移动应用程序是 client,它将进一步拥有它的用户。

我遵循了步骤 mentioned by Taylor and also read about it here。简而言之,我遵循了以下步骤:

  1. 已安装 laravel/passport
  2. 创建了一个网站用户。
  3. 生成的通行证密钥php artisan passport:install
  4. 使用 php artisan passport:client
  5. 生成 client_idclient_secret
  6. web.php
  7. 中添加了 redirectioncallback 路线
  8. 授权用户并获得最终访问令牌。

然后我尝试调用 api/user( Header Authorization 包含值 Bearer eyJ0eXAiOiJKV1...(token)

我收到了数据。非常简单和整洁。

但我的应用程序用户不会知道这些详细信息。所以我想到配置 Password Grant Tokens 完全符合我的要求。

现在开始真正的头痛。在过去的 3 天里,我一直在尝试设置它并不断获得

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

我几乎尝试了我在网上遵循的所有指南:, Add Atleast One Scope Solution, P100Y Issue

但我仍然遇到 invalid client 错误。这是我通过 POSTMAN 传递给 oauth/token:

的内容
{
    "grant_type": "password,"
    "client_id": "3,"
    "client_secret": "8BUPCSyYEdsgtZFnD6bFG6eg7MKuuKJHLsdW0k6g,"
    "username": "test@gmail.com,"
    "password": "123456,"
    "scope": ""
}

如有任何帮助,我们将不胜感激。

首先检查您的凭据是否正确,其次检查您的模型 table 使用 \Laravel\Passport\HasApiTokens 特征是否包含 email 列,因为默认情况下它用于识别验证凭据时的用户。如果您的 table 有 username 列或任何其他用于验证凭据的列,您必须在该模型中定义函数 findForPassport。像这样,

public function findForPassport($username) {
       return self::where('username', $username)->first(); // change column name whatever you use in credentials
    }

我使用用户名和密码列来验证用户, 在 {project_directory}\vendor\laravel\passport\src\Bridge\UserRepository.php

此函数验证您的凭据,

public function getUserEntityByUserCredentials($username, $password, $grantType, ClientEntityInterface $clientEntity)
    {
        if (is_null($model = config('auth.providers.users.model'))) {
            throw new RuntimeException('Unable to determine user model from configuration.');
        }

        if (method_exists($model, 'findForPassport')) { // if you define the method in that model it will grab it from there other wise use email as key 
            $user = (new $model)->findForPassport($username);
        } else {
            $user = (new $model)->where('email', $username)->first();
        }

        if (! $user || ! $this->hasher->check($password, $user->password)) {
            return;
        }

        return new User($user->getAuthIdentifier());
    }

注意第二个 if 语句,您将了解那里发生了什么。

希望对您有所帮助:)

我遇到了同样的问题,并通过设置 basic.auth headers 解决了问题,其中 client_id 作为用户名,secret 作为密码。

然后它运行良好。

我已经设法让 Laravel Passport - Password_Grant_Token 通过 RESTED(POSTMAN 类服务)工作,无需任何额外的控制器或中间件。这是我成功做到的方法!

在 laravel doc's here
中安装默认 Auth-Scaffolding 安装通行证doc's here
通过auth-scaffolding
注册用户 转到 RESTED 或 POSTMAN,或任何其他类似服务
在 oauth_clients table 中检查您的 form_params
中的数据 通过 Request_body_form_data 而不是 headers 的 RESTED 写下你的 forms_params 并发送 POST 请求到 */oauth/token(需要完整的 url)

(需要form_params分别是grant_type、client_id、client_secret、用户名和密码)

您应该进入 return 一个带有 4 个键(token_type、expires_in、access_token 和 refresh_token)的 object 和一个状态 200 OK.

如果到目前为止一切顺利...

打开另一个 RESTED window:

向 /api/user 发送 GET 请求(同样需要完整的 url) 在 headers 中写入 2 name-value 对 (Accept => application/json, Authorization => Bearer ACCESS_TOKEN_GOTTEN_IN_PREVIOUS_REQUEST (to /oauth/token)

应该就是这样。您应该得到一个用户 object 作为来自 /api/user 的响应。

尝试使用 php artisan passport:client --password 创建一个新的密码客户端 那么很可能不会将用户分配给该密码客户端。编辑数据库行并向其添加现有用户 ID。

{
    "grant_type": "password,"
    "client_id": "" <- edited and added user id
    "client_secret": "8BU......," <- new secret
    "username": "test@gmail.com," <- email of above added user id
    "password": "123456,"<- password 
    "scope": ""
}

希望你现在能拿到token

这可能会帮助您指明正确的方向,因为我们正在自己实施密码 g运行t。

1 - 在您的第 4 步中而不是 运行宁此:

php artisan passport:install

运行以下创建密码g运行t客户端:

php artisan passport:client --password

上面的命令将给出一个后续问题来设置您的密码 G运行t 客户端的名称。请务必在您的数据库中获取此新记录的 ID 和密码。

2 - 您的 POSTMAN Post 请求对象应包装在类似于以下内容的对象中:

'form_params' => [
    'grant_type' => 'password',
    'client_id' => 'my_client-id',
    'client_secret' => 'my_client-secret',
    'username' => 'username or email', <-pass through variables or something
    'password' => 'my-user-password', <- pass through variables or something
    'scope' => '',
],

2016 年 10 月 12 日更新 1:

在进一步调查此问题后,我 运行 进入了与您所在的完全相同的位置,并被迫潜入护照的兔子洞。

目前,据我所见,系统在需要 'password' 时将客户端标识符设置为 'authorization_code'。我正在研究如何解决您遇到的这个问题,因为我也 运行 遇到过这个问题。我将 post 编写代码来帮助人们了解我去过的地方和我一直在做的事情,但是 2:40 现在我需要睡觉了。

更新 2 10/12/2016

现在已经调试这个问题 7 个小时了。护照中有一种方法可以验证客户端。此方法接受您在对象中添加的输入(如上所述),并尝试根据您传入的内容通过客户端存储库 class 获取客户端实体。如果找到客户端,它将被检查以查看客户端实体的实例是否真正存在于客户端实体接口中,它看起来像是从数据库中提取客户端的凭据。但是,有一段代码 returns NULL 从我在测试中得到的。到目前为止,所有字段都已正确引入,但存储库和界面之间似乎存在混淆。这是导致抛出错误的原因。

最后我觉得我离解决这个问题越来越近了。非常感谢您的耐心等待。 =)

更新 3 10/12/2016

经过长时间的调试,我找到了最初的问题。有些字段不匹配。简而言之,这是一个设置问题。

所以

这种情况的解决方法是:

仔细检查数据库中的所有字段,并传入 所有 凭据。一直到句点、破折号、空格密码、客户端ID、客户端密码、有效重定向 URIs/URLs、grant_types 和范围(如果您正在使用它们):

确保数据库中的客户端在 "password_client" 列下的 ENUM 为 1,否则您需要使用上面提到的 php artisan 命令创建一个,我将参考这里:

php artisan passport:client --password

确保您传递的秘密与数据库中为该客户列出的秘密相匹配

确保您传递的 ID 匹配并且是整数数据类型。

确保客户端有某种名称

使用密码g运行ts

时不用担心user_id栏

确保路线正确

确保您输入的电子邮件(用户名)是您数据库中用户 table 中的实际用户(或者任何 table 您自定义的 laravel 5.3 系统接受作为您的用户 table,我将添加一个 link 关于如何自定义 laravel 5.3 系统以接受不同的用户 table 作为默认值(如果需要的话)。

确保 grant_type 拼写正确

确保您已设置为接受响应不记名令牌(即 access_token 和 refresh_token)。

除此之外,我在本答案的上述部分概述的初始步骤应该会让您回到正确的轨道上。这里还有其他人确实提到了一些类似的步骤,这些步骤很有帮助,但也解决了与单独问题相关的相同错误(我确定这是与其特定系统设置相关的设置问题的结果)。

不过希望这对您有所帮助。

在护照服务器上设置客户端时检查redirect/callback url。检查从中获取客户端 ID 和机密的条目,重定向 URL 是否正确。

我遇到了同样的错误,发现重定向 URL 不正确。

它需要指向 /callback 路由(在 Taylor 给出的示例中)

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

表示您当前发送的 client_id 和 client_secret 是以下之一:

    正在发送的
  1. client_id 和 client_secret 未在您的 oauth 服务器
  2. 中注册 正在发送的
  3. client_id 和 client_secret 不是您在 post 正文
  4. 中指定的授权类型

For me, the password_client column value for that particular client was 0. i manually changed it to 1 but it didn't help. – Kanav Oct 4 at 3:25

当我读到你对某些答案的评论时,很明显你使用了错误类型的 client_id 和 client_secret 作为你的密码授予流程,所以你的情况是后者.您可以通过为您提供的 client_id 和 client_secret

在 oauth_clients table 中找到条目来验证这一点
"grant_type": "password,"    
"client_id": "3,"
"client_secret": "8BUPCSyYEdsgtZFnD6bFG6eg7MKuuKJHLsdW0k6g,"

SELECT * FROM oauth_clients WHERE id = 3 AND secret = '8BUPCSyYEdsgtZFnD6bFG6eg7MKuuKJHLsdW0k6g' AND password_client=1;

在您的 oauth_clients table 中检查您提供的 client_id 和 client_secret 是否存在用于密码授予流程 你的 oauth 服务器。而且您也不能通过简单地切换该列的值来手动更改客户端类型,您必须为密码授予类型创建一个新客户端

php artisan migrate

此命令将迁移 laravel/passport 迁移文件,为 laravel/passport 当前支持的每种类型生成两个默认客户端。您还可以使用

创建密码授予流程的客户端
php artisan passport:client --password

当您有一个密码授予类型的新客户端时,再次尝试 POST 到 /oauth/token 以使用您新生成的 client_id 和 client_secret

生成令牌

必须尝试 运行 php artisan config:cache 完成所有护照命令后。

使用下面的代码生成访问令牌,它以前对我有用:

$request->request->add([
      'client_id' => '2',
      'client_secret' => 'm3KtgNAKxq6Cm1WC6cDAXwR0nj3uPMxoRn3Ifr8L',
      'grant_type' => 'password',
      'username' => 'support@eliteride.co.uk',
      'password' => 'pass22'
    ]);
    $tokenRequest = $request->create('/oauth/token', 'POST', $request->all());

    $token =  \Route::dispatch($tokenRequest);

你可以定义两个变量,比如

$client_id = '111';
$client_secret = '1212';

条件在你的函数中是这样的

protected $clientID = '578324956347895';
protected $clinetSecret ='hflieryt478';

public function index(Request $request)
{

    if (!($request->input('clientID') && $request->input('clinetSecret'))) {
        return false;
    }

    $project = User::all();

   return $project
}

彻底检查授权类型。

{
    "grant_type": "password",
    "client_id": 2,
    "client_secret": 
    "username": ,
    "password": 
    "scope": ""
}

在上面的例子中,它说的是密码。现在检查table:oauth_clients 并确保 password_client = 1

列的值

或查找带有 password_client = 1

的条目

我也遇到了同样的问题,我从这个 link 得到了解决方案。请检查一下。 https://github.com/laravel/passport/issues/71

它说: 你像往常一样打电话给 /oauth/token 来获取你的令牌。但是用 custom_request 的 grant_type 来做到这一点。您需要将 byPassportCustomRequest($request) 方法添加到您的 User 模型 (或您配置为使用 Passport 的任何模型)。如果您能够通过请求对用户进行身份验证,该方法将接受 Illuminate\Http\Request 和 return 用户模型,否则它将 return null。

如果您尝试了所有方法但仍然无法正常工作,请尝试此解决方案!! 只给出范围 *.

$query = http_build_query([
    'client_id' => 1,
    'redirect_uri' => 'http://localhost:3000/callback',
    'response_type' => 'code',
    'scope' => '*'
]);

就我而言,这就是解决方案。我检查了

我遇到了同样的问题。当您执行 php artisan passport:install 时,它会向您发出两种类型的机密,一种用于 CLIENT 授权类型,另一种用于 PASSWORD 授权类型。

我正在使用 CLIENT 密钥来颁发 PASSWORD 令牌。一旦我改变了它,我就能够正常生成 access_tokenrefresh_token

就我而言,解决方案是将其包装在 Form-data 中, 如果你用邮递员使用普通参数,不要错过它,它不会起作用, 确保使用设置为 FORM-DATA 的正文请求。

希望这可以节省我调试此问题的时间:

我钻进了兔子洞,找出身份验证不起作用的原因。原来我在我的 UsersTableSeeder 中不小心对我的密码进行了两次哈希处理,这就是哈希检查失败的原因。

可能值得检查列出的其他答案是否不适合您。

确保您没有尝试获取带有散列 client_secret... 如果您在 AppServiceProvider 内使用 Passport::hashClientSecrets(); 散列客户端机密,生成的令牌将仅在终端输出 中显示一次 。松开此令牌,它将永远丢失。

设置护照时我很匆忙,忘记了我正在散列生成的客户端机密...

我的请求正文应该包含一个 加密的客户端机密,但我从数据库中复制并粘贴了一个加密的机密。

要解决此问题,请立即保存您的客户端机密,或者删除 Passport::hashClientSecrets(); 并创建一个 客户端。

尝试在 AppServiceProvider 文件中注释掉这一行 Passport::hashClientSecrets();。您不能使用散列客户端机密。

我通过确保在 oauth_clients table 我的客户将列 password_client 设置为 1:

来修复它

来源:https://github.com/laravel/passport/issues/589#issuecomment-357515110

There may be quite scenarios for the above issue.I will explain it one by one. You always need to pass application/json header .

  1. Make sure the client id and secret is in the oauth_clients and you passed those parameter correctly.In order to generate those client id and secret use php artisan passport:install.
  2. Make sure to use password grant client . To identify that goto oauth_clients table and check if password_client is set to 1 and personal_access_client is set to 0 and revoked to 0 . I hope this will solve the issue . Thank you

我遇到了同样的问题,我尝试了以上所有解决方案,但都没有成功。

所以我重新加载了表格,重新创建了用户、护照客户端并解决了。我的解决方案是重置所有内容:

php artisan migrate:fresh

php artisan passport:client --password