簡體   English   中英

Laravel Passport 密碼授予 - 客戶端身份驗證失敗

[英]Laravel Passport Password Grant - Client authentication failed

在聽到很多關於 laravel 護照的信息后,我想到將它實施到我的新項目中,我的要求是創建一個 API 將在移動應用程序中使用。

所以我的移動應用程序是一個client ,它將進一步擁有它的用戶。

我遵循了Taylor 提到的步驟,並在此處閱讀了相關內容。 簡而言之,我遵循了以下步驟:

  1. 安裝laravel/passport
  2. 創建了一個網站用戶。
  3. 生成的護照密鑰php artisan passport:install
  4. 使用php artisan passport:client生成client_idclient_secret
  5. web.php添加redirectioncallback路由
  6. 授權用戶並獲得最終訪問令牌。

然后我嘗試調用api/user ( Header Authorization包含值Bearer eyJ0eXAiOiJKV1...(token)

我收到了數據。 非常簡單和整潔。

但我的應用程序用戶不會知道這些詳細信息。 所以我想到配置完全符合我要求的密碼授予令牌

現在開始真正的頭痛。 在過去的 3 天里,我一直在嘗試進行設置,並且不斷得到

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

我幾乎嘗試了我在網上遵循的所有指南: 重定向問題添加至少一個 Scope 解決方案P100Y 問題等。

但我仍然收到invalid client錯誤。 這是我通過 POSTMAN 傳遞給oauth/token的內容:

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

任何幫助,將不勝感激。

首先檢查您的憑據是否正確,其次檢查您的模型表,該表使用\\Laravel\\Passport\\HasApiTokens特征是否包含email列,因為默認情況下它用於在驗證憑據時識別用戶。 如果您的表具有username findForPassport或用於驗證憑據的任何其他列,您必須在該模型中定義一個函數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 語句,你會知道那里發生了什么。

希望這有幫助:)

這可能有助於為您指明正確的方向,因為我們正在自己實施密碼授予。

1 - 在你的第 4 步而不是運行這個:

php artisan passport:install

運行以下命令來創建您的密碼授權客戶端:

php artisan passport:client --password

上面的命令將給出一個后續問題來設置您的密碼授予客戶端的名稱。 請務必在您的數據庫中獲取此新記錄的 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:

在進一步調查這個問題時,我遇到了你所在的完全相同的地方,並被迫潛入護照的兔子洞。

目前,從我所看到的系統已將客戶端標識符設置為“authorization_code”,當它需要“密碼”時。 我正在研究如何解決您遇到的這個問題,因為我也遇到過。 我將發布代碼以幫助人們了解我去過的地方和我一直在做的事情,但現在是凌晨 2:40,所以我需要休息一下。

更新 2 10/12/2016

現在已經調試了 7 個小時的問題。 護照中有一種方法可以驗證客戶端。 此方法采用您在對象中添加的輸入(如上所述)並嘗試根據您傳入的內容通過客戶端存儲庫類獲取客戶端實體。如果找到客戶端,則將檢查它是否客戶端實體的實例確實存在於客戶端實體接口中,看起來像是從數據庫中提取客戶端的憑據。 但是,有一段代碼從我的測試中得到的返回 NULL。 到目前為止,所有字段都被正確引入,但存儲庫和界面之間似乎存在混淆。 這導致錯誤被拋出。

最后,我覺得我離解決這個問題越來越近了。 非常感謝您的耐心等待。 =)

更新 3 10/12/2016

經過長時間的調試,我發現了最初的問題。 有些字段不匹配。 簡而言之,這是一個設置問題。

所以

這種情況下的解決辦法是:

雙重檢查所有字段在傳入所有憑據的數據庫中。精確到句點、破折號、空格密碼、客戶端 ID、客戶端機密、有效重定向 URI/URL、grant_types 和范圍(如果您正在使用它們):

確保數據庫中的客戶端在“password_client”列下的 ENUM 為 1,如果不是,則需要使用上面提到的 php artisan 命令創建一個,我將在此處引用:

php artisan passport:client --password

確保您傳入的機密與您的數據庫中為該客戶端列出的內容相匹配

確保您傳遞的 id 匹配並且是整數數據類型。

確保客戶端有某種名稱

使用密碼授權時不要擔心 user_id 列

確保路線正確

確保您輸入的電子郵件(用戶名)是您數據庫中用戶表中的實際用戶(或您自定義 laravel 5.3 系統接受為用戶表的任何表,我將添加有關如何自定義 laravel 5.3 的鏈接系統在需要時接受不同的用戶表作為默認值)。

確保 grant_type 拼寫正確

確保您已設置為接受響應承載令牌(即 access_token 和 refresh_token)。

除此之外,我在本答案的上述部分中概述的初始步驟應該會讓您回到正確的軌道上。 這里還有其他人確實提到了一些有用的類似步驟,但也解決了與單獨問題相關的相同錯誤(我確定這是與其特定系統設置相關的設置問題的結果)。

我希望這會有所幫助。

您是否嘗試在所有護照命令之后運行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);
{"error":"invalid_client","message":"Client authentication failed"}

意味着您當前發送的 client_id 和 client_secret 是以下之一:

  1. 正在發送的 client_id 和 client_secret在您的 oauth 服務器中注冊
  2. 發送的 client_id 和 client_secret不是您在帖子正文中指定的授權類型

對我來說,該特定客戶端的 password_client 列值為 0。我手動將其更改為 1,但沒有幫助。 – Kanav 10 月 4 日 3:25

當我閱讀您對某些答案的評論時,很明顯您對密碼授予流程使用了錯誤類型的 client_id 和 client_secret,因此您的情況是后者。 您可以通過在 oauth_clients 表中為您提供的 client_id 和 client_secret 查找條目來驗證這一點

"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 表中檢查您提供的 client_id 和 client_secret 是否存在用於oauth 服務器中的密碼授予流程 而且您不需要通過簡單地切換該列的值來手動更改客戶端的類型,您必須為密碼授予類型創建一個新的客戶端

php artisan migrate

該命令將遷移 laravel/passport 遷移文件,為 laravel/passport 當前支持的每種類型生成兩個默認客戶端。 您還可以為密碼授予流程創建一個客戶端

php artisan passport:client --password

當您有密碼授予類型的新客戶端時,請再次嘗試 POST 到 /oauth/token 以使用新生成的 client_id 和 client_secret 生成令牌

確保您沒有嘗試使用散列的client_secret獲取令牌...如果您使用Passport::hashClientSecrets();散列客戶端機密Passport::hashClientSecrets(); AppServiceProvider ,生成的令牌只會在終端輸出中顯示一次 松開這個令牌,它就永遠丟失了。

當我設置護照並忘記我正在散列生成的客戶端機密時,我很匆忙......

我的請求正文應該包含一個加密的客戶端機密,但我從數據庫中復制並粘貼了一個加密的機密。

要解決此問題,請立即保存您的客戶端機密,或刪除Passport::hashClientSecrets(); 並創建一個客戶端。

我遇到了同樣的問題,並通過設置 basic.auth 標頭來解決,其中 client_id 作為用戶名,secret 作為密碼。

然后它工作得很好。

徹底檢查授予類型。

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

在上面的例子中,它說密碼。 現在檢查表: oauth_clients並確保password_client = 1列的值password_client = 1

或查找password_client = 1的條目

我已經設法讓 Laravel Passport - Password_Grant_Token 通過 RESTED(POSTMAN 之類的服務)工作,而無需任何額外的控制器或中間件。 這是我設法做到的!

在 laravel文檔的此處安裝默認的 Auth-Scaffolding
此處安裝護照文件
通過 auth-scaffolding 注冊用戶
轉到 RESTED 或 POSTMAN,或任何其他類似服務
檢查 oauth_clients 表中 form_params 的數據
使用 RESTED 通過 Request_body_form_data not headers 寫你的 forms_params 並將 POST 請求發送到 */oauth/token(需要完整的 url)

(所需的 form_params 是 grant_type、client_id、client_secret、用戶名和密碼)

您應該返回一個帶有 4 個鍵(token_type、expires_in、access_token 和 refresh_token)和 200 OK 狀態的對象。

如果到目前為止一切都成功...

打開另一個 RESTED 窗口:

向 /api/user 發送一個 GET 請求(同樣需要完整的 url)在頭文件中寫入 2 個名稱-值對(Accept => application/json, Authorization => Bearer ACCESS_TOKEN_GOTTEN_IN_PREVIOUS_REQUEST(到 /oauth/token)

應該就是這樣。 您應該從 /api/user 獲取用戶對象作為響應。

嘗試使用 php artisanpassport: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

在護照服務器上設置客戶端時檢查重定向/回調 url。 檢查從中獲取客戶端 ID 和密鑰的條目,以確保重定向 URL 是正確的。

我遇到了同樣的錯誤,發現重定向 URL 不正確。

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

我也遇到了同樣的問題,我從這個鏈接中得到了解決方案。 請檢查一下。 https://github.com/laravel/passport/issues/71

它說:您像往常一樣調用 /oauth/token 來獲取令牌。 但是使用custom_request 的grant_type 這樣做。 您需要將byPassportCustomRequest($request)方法添加到您的User 模型(或您配置為使用 Passport 的任何模型)。 如果您能夠通過請求對用戶進行身份驗證,該方法將接受 Illuminate\\Http\\Request 並返回用戶模型,否則它將返回 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 中對密碼進行了兩次哈希處理,這就是哈希檢查失敗的原因。

如果列出的其他答案對您不起作用,可能值得檢查。

嘗試注釋掉這一行Passport::hashClientSecrets(); AppServiceProvider文件中。 您不能使用散列的客戶端機密。

我通過確保在 oauth_clients 表中我的客戶端將 password_client 列設置為 1 來修復它:

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

上述問題可能有相當多的場景,我會一一解釋。 你總是需要傳遞 application/json header 。

  1. 確保客戶端 ID 和密碼在 oauth_clients 中並且您正確傳遞了這些參數。為了生成這些客戶端 ID 和密碼,請使用 php artisanpassport:install。
  2. 確保使用 password grant client 。 識別 goto oauth_clients 表並檢查 password_client 是否設置為 1 並且 personal_access_client 設置為 0 並撤銷為 0 。 我希望這將解決問題。 謝謝

laravel 9.x中,如果您的AuthServiceProvider boot方法中有Passport::hashClientSecrets() ,也會拋出錯誤: Client authentication failed 不知道為什么,但刪除它只是節省了我的時間。

我遇到了同樣的問題,我嘗試了上述所有解決方案,但沒有成功。

所以我只是重新加載了表格,重新創建了用戶,護照客戶端並解決了。 我的解決方案是重置所有內容:

php artisan migrate:fresh (將清理您的數據庫。)

php artisan passport:client --password

您可以定義兩個變量,例如

$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
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM