国产av日韩一区二区三区精品,成人性爱视频在线观看,国产,欧美,日韩,一区,www.成色av久久成人,2222eeee成人天堂

Passport OAuth 認證

Passport OAuth 認證


Laravel Passport

介紹

在 Laravel 中,實現(xiàn)基于傳統(tǒng)表單的登陸和授權已經(jīng)非常簡單,但是如何滿足 API 場景下的授權需求呢?在 API 場景里通常通過令牌來實現(xiàn)用戶授權,而非維護請求之間的 Session 狀態(tài)。在 Laravel 項目中使用 Passport 可以輕而易舉地實現(xiàn) API 授權認證,Passport 可以在幾分鐘之內為你的應用程序提供完整的 OAuth2 服務端實現(xiàn)。Passport 是基于由 Andy Millington 和 Simon Hamp 維護的 League OAuth2 server 建立的。

{note} 本文檔假定你已熟悉 OAuth2 。如果你并不了解 OAuth2 ,閱讀之前請先熟悉下 OAuth2 的 常用術語 和特性。

安裝

在開始之前,請通過 Composer 包管理器安裝 Passport:

composer require laravel/passport

Passport 服務提供器使用框架注冊自己的數(shù)據(jù)庫遷移目錄,因此在注冊提供器后,就應該運行 Passport 的遷移命令來自動創(chuàng)建存儲客戶端和令牌的數(shù)據(jù)表:

php artisan migrate

接下來,運行 passport:install 命令來創(chuàng)建生成安全訪問令牌時所需的加密密鑰,同時,這條命令也會創(chuàng)建用于生成訪問令牌的「個人訪問」客戶端和「密碼授權」客戶端:

php artisan passport:install

上面命令執(zhí)行后,請將 Laravel\Passport\HasApiTokens Trait 添加到 App\User 模型中,這個 Trait 會給你的模型提供一些輔助函數(shù),用于檢查已認證用戶的令牌和使用范圍:

<?php
    namespace App;
    use Laravel\Passport\HasApiTokens;
    use Illuminate\Notifications\Notifiable;
    use Illuminate\Foundation\Auth\User as Authenticatable;
    class User extends Authenticatable{ 
       use HasApiTokens, Notifiable;
     }

接下來,在 AuthServiceProviderboot 方法中調用 Passport::routes 函數(shù)。這個函數(shù)會注冊發(fā)出訪問令牌并撤銷訪問令牌、客戶端和個人訪問令牌所必需的路由:

<?php
    namespace App\Providers;
    use Laravel\Passport\Passport;
    use Illuminate\Support\Facades\Gate;
    use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
    class AuthServiceProvider extends ServiceProvider{ 
    /**
     * 應用程序的策略映射。
     *
     * @var array
     */   
     protected $policies = [  
           'App\Model' => 'App\Policies\ModelPolicy',  
            ];   
     /**
     * 注冊任何認證/授權服務。
     *
     * @return void
     */   
     public function boot()
         {   
              $this->registerPolicies();        
              Passport::routes();    
         }
     }

最后,將配置文件 config/auth.php 中授權看守器 guardsapidriver 選項改為 passport。此調整會讓你的應用程序在在驗證傳入的 API 的請求時使用 Passport 的 TokenGuard 來處理:

'guards' => [
    'web' => [ 
           'driver' => 'session',        
           'provider' => 'users',    
          ],    
     'api' => [   
              'driver' => 'passport',        
              'provider' => 'users',    
            ],
           ],

自定義遷移

如果你不打算使用 Passport 的默認遷移,你應該在 AppServiceProviderregister 方法中調用 Passport::ignoreMigrations 方法。 你可以用這個命令 php artisan vendor:publish --tag=passport-migrations 導出默認遷移。

默認情況下,Passport 使用字段 「user_id」標識用戶。如果想使用不同的字段標識用戶 (例如:uuid),可以修改默認的 Passport 遷移文件。

前端快速上手

{note} 為了使用 Passport 的 Vue 組件,你必須使用 Vue JavaScript 框架。這些組件也使用了 Bootstrap CSS 框架。然而,如果你不打算使用這些工具,這些組件對于你自己的前端組件編寫也十分有價值。

Passport 提供了一系列 JSON API ,你可以用它們來允許你的用戶創(chuàng)建客戶端和個人訪問令牌。然而,編寫與這些 API 交互的前端代碼可能是很占用時間的。因此,Passport 也包括了預編譯的 Vue 組件,你可以直接使用或將其作為你自己的前端參考。

要使用 Passport 的 Vue 組件,使用 vendor:publish Artisan 命令:

php artisan vendor:publish --tag=passport-components

被發(fā)布的組件將會被放到 resources/js/components 目錄下。當組件被發(fā)布后,你應該在你的 resources/js/app.js 文件中注冊它們:

Vue.component(
    'passport-clients',    
    require('./components/passport/Clients.vue').default);
    Vue.component(
        'passport-authorized-clients',    
        require('./components/passport/AuthorizedClients.vue').default
       );
     Vue.component(
          'passport-personal-access-tokens',    
          require('./components/passport/PersonalAccessTokens.vue').default
        );

{note} 在 Laravel v5.7.19 之前,在注冊組件時添加 “.default” 會導致控制臺錯誤。有關此更改的解釋,請參閱 Laravel Mix v4.0.0 發(fā)布說明.

在注冊了組件后,請確保運行 npm run dev 來重新編譯你的資源。 當你重編譯你的資源后,你可以將組件放到你應用的模板中以開始創(chuàng)建客戶端和個人訪問令牌:

<passport-clients></passport-clients>
<passport-authorized-clients></passport-authorized-clients><
passport-personal-access-tokens></passport-personal-access-tokens>

部署 Passport

第一次在你的生產環(huán)境部署 Passport 時,你大概需要運行 passport:keys 命令。這個命令生成 Passport 生成訪問令牌所需的密鑰。生成的密鑰一般情況下不應放在版本控制中:

php artisan passport:keys

可以使用 Passport::loadKeysFrom 方法來自定義 Passport 密鑰的加載路徑:

/**
 * 注冊認證 / 授權服務
 *
 * @return void
 */
 public function boot(){
     $this->registerPolicies();    
     Passport::routes();    
     Passport::loadKeysFrom('/secret-keys/oauth');
    }

配置

令牌的有效期

默認情況下,Passport 發(fā)放的訪問令牌是有一年有效期的。但是如果你想自定義訪問令牌的有效期,可以使用 tokensExpireInrefreshTokensExpireIn 方法。上述兩個方法同樣需要在 AuthServiceProviderboot 方法中調用:

/**
 * 注冊認證 / 授權服務
 *
 * @return void
 */
 public function boot(){
     $this->registerPolicies();    
     Passport::routes();    
     Passport::tokensExpireIn(now()->addDays(15));    
     Passport::refreshTokensExpireIn(now()->addDays(30));
   }

覆蓋默認模型

可以自由擴展 Passport 使用的模型,通過 Passport 類自定義模型覆蓋默認模型:

use App\Models\Passport\Client;
use App\Models\Passport\AuthCode;
use App\Models\Passport\TokenModel;
use App\Models\Passport\PersonalAccessClient;
/**
 * 注冊認證 / 授權服務
 *
 * @return void
 */
 public function boot(){
     $this->registerPolicies();    
     Passport::routes();    
     Passport::useClientModel(Client::class);    
     Passport::useTokenModel(TokenModel::class);    
     Passport::useAuthCodeModel(AuthCode::class);    
     Passport::usePersonalAccessClientModel(PersonalAccessClient::class);
    }

發(fā)放訪問令牌

熟悉 OAuth2 的開發(fā)者一定知道, OAuth2 中必不可少的部分就是授權碼。當使用授權碼時,客戶端應用程序會將用戶重定向到你的服務器,他們將批準或拒絕向客戶端發(fā)出訪問令牌的請求。

管理客戶端

首先,構建需要與應用程序 API 交互的應用程序,開發(fā)人員將需要通過創(chuàng)建一個「客戶端」來注冊自己的應用程序。一般來說,這包括在用戶批準其授權請求后,提供其應用程序的名稱和應用程序可以重定向到的 URL。

The passport:client 命令

創(chuàng)建客戶端最簡單的方式是使用 Artisan 命令 passport:client,你可以使用此命令創(chuàng)建自己的客戶端,用于測試你的 OAuth2 的功能。在你執(zhí)行 client 命令時,Passport 會提示你輸入有關客戶端的信息,最終會給你提供客戶端的 ID 和 密鑰:

php artisan passport:client

Redirect URLs

當有多個重定向 URL 白名單時,可以在 passport:client 命令提示輸入 URL 時,使用逗號分隔來指定:

http://example.com/callback,http://examplefoo.com/callback

{note} 任何包含逗號的 URL 都必須進行編碼。

JSON API

考慮到你的用戶無法使用 client 命令,Passport 為此提供了可用于創(chuàng)建「客戶端」的 JSON API。這樣你就不用再花時間編寫控制器來創(chuàng)建、更新和刪除客戶端。

然而,你仍舊需要基于 Passport 的 JSON API 開發(fā)一套前端界面,為你的用戶提供管理客戶端的面板。下面我們會列出所有用于管理客戶端的 API,為了方便起見,我們使用 Axios 來演示對端口發(fā)出 HTTP 請求。

這個 JSON API 由 webauth 兩個中間件保護,所以只能從應用程序中調用,不能從外部調用。

{tip} 如果你不想自己實現(xiàn)整個客戶端管理的前端界面,可以使用  前端快速上手 在幾分鐘內組建一套功能齊全的前端界面。

GET /oauth/clients

此路由會返回認證用戶的所有客戶端。主要用途是列出所有用戶的客戶端,以便他們可以編輯或刪除它們:

axios.get('/oauth/clients')
    .then(response => {
        console.log(response.data); 
      });

POST /oauth/clients

此路由用于創(chuàng)建新客戶端。它需要兩個參數(shù):客戶端的名稱 name 和授權后回調的 URL redirect。在批準或拒絕授權請求后,用戶會被重定向到 redirect 參數(shù)提供的鏈接。

當客戶端創(chuàng)建后,會返回客戶端的 ID 和密鑰??蛻舳丝梢允褂眠@兩個值從你的授權服務請求訪問令牌 (Access token) 。該路由會返回新的客戶端實例:

const data = {
    name: 'Client Name',
    redirect: 'http://example.com/callback'};
    axios.post('/oauth/clients', data)
        .then(response => {
                console.log(response.data); 
           })
         .catch (response => {
                // 在response里列出錯誤詳情...    
             });

PUT /oauth/clients/{client-id}

此路由用于更新客戶端信息。它需要兩個參數(shù):客戶端的名稱 name 和授權后回調的 URL redirect。在批準或拒絕授權請求后,用戶會被重定向 redirect 到這個鏈接。此路由會返回更新后的客戶端實例:

const data = {
    name: 'New Client Name',
    redirect: 'http://example.com/callback'};
    axios.put('/oauth/clients/' + clientId, data)
        .then(response => {
                console.log(response.data);    
              })    
         .catch (response => { 
                // 在response里列出錯誤詳情...    
            });

DELETE /oauth/clients/{client-id}

此路由用于刪除客戶端 (client):

axios.delete('/oauth/clients/' + clientId)
    .then(response => {  
          //   
       });

請求令牌

授權時的重定向

客戶端創(chuàng)建之后,開發(fā)者會使用此客戶端的 ID 和密鑰來請求授權代碼,并從應用程序訪問令牌。首先,接入應用的用戶向你應用程序的 /oauth/authorize 路由發(fā)出重定向請求,示例如下:

Route::get('/redirect', function () {
    $query = http_build_query([ 
           'client_id' => 'client-id',        
           'redirect_uri' => 'http://example.com/callback',        
           'response_type' => 'code',        
           'scope' => '',    
        ]);    
      return redirect('http://your-app.com/oauth/authorize?'.$query);
    });

{tip} 注意,路由 /oauth/authorize 已經(jīng)在 Passport::routes 方法中定義。你不需要手動定義此路由。

批準請求

接收到授權請求時,Passport 會自動向用戶顯示一個模版頁面,允許用戶批準或拒絕授權請求。如果用戶批準請求,他們會被重定向回接入的應用程序指定的 redirect_uri。redirect_uri 必須和客戶端創(chuàng)建時指定的 redirect 鏈接完全一致。

如果你想自定義授權確認頁面,可以使用 Artisan 命令 vendor:publish 發(fā)布 Passport 的視圖。發(fā)布后的視圖文件存放在 resources/views/vendor/passport

php artisan vendor:publish --tag=passport-views

將授權碼轉換為訪問令牌

用戶批準授權請求后,會被重定向回接入的應用程序。然后接入應用應該將通過 POST 請求向你的應用程序申請訪問令牌。請求應該包括當用戶批準授權請求時由應用程序發(fā)出的授權碼。在下面的例子中,我們使用 Guzzle HTTP 庫來實現(xiàn)這次 POST 請求:

Route::get('/callback', function (Request $request) {
    $http = new GuzzleHttp\Client;    
    $response = $http->post('http://your-app.com/oauth/token', [  
          'form_params' => [      
                'grant_type' => 'authorization_code',            
                'client_id' => 'client-id',            
                'client_secret' => 'client-secret',            
                'redirect_uri' => 'http://example.com/callback',            
                'code' => $request->code,        
               ],    
            ]);    
      return json_decode((string) $response->getBody(), true);
   });

路由 /oauth/token 返回的 JSON 響應中會包含 access_token 、refresh_tokenexpires_in 屬性。expires_in 屬性包含訪問令牌的有效期(單位:秒)。

{tip} 像 /oauth/authorize 路由一樣,/oauth/token 路由在 Passport::routes 方法中定義了,你沒必要手動去定義它。默認情況下,此路由使用 “ThrottleRequests” 中間件的設置進行限流。

刷新令牌

如果你的應用程序發(fā)放了短期的訪問令牌,用戶將需要通過在發(fā)出訪問令牌時提供給他們的刷新令牌來刷新其訪問令牌。在下面的例子中,我們使用 Guzzle HTTP 庫來刷新令牌:

$http = new GuzzleHttp\Client;
$response = $http->post('http://your-app.com/oauth/token', [ 
   'form_params' => [  
         'grant_type' => 'refresh_token',        
         'refresh_token' => 'the-refresh-token',        
         'client_id' => 'client-id',        
         'client_secret' => 'client-secret',        
         'scope' => '',    
        ],]);
   return json_decode((string) $response->getBody(), true);

路由 /oauth/token 會返回一個 JSON 響應,其中包含 access_token 、refresh_tokenexpires_in 屬性。expires_in 屬性包含訪問令牌的有效時間(單位:秒)。

密碼授權令牌

OAuth2 密碼授權機制可以讓你自己的客戶端(如移動應用程序)使用郵箱地址或者用戶名和密碼獲取訪問令牌。如此一來你就可以安全地向自己的客戶端發(fā)出訪問令牌,而不需要遍歷整個 OAuth2 授權代碼重定向流程

創(chuàng)建密碼授權客戶端

在應用程序通過密碼授權機制來發(fā)布令牌之前,在 passport:client 命令后加上 --password 參數(shù)來創(chuàng)建密碼授權的客戶端。如果你已經(jīng)運行了 passport:install 命令,則不需要再運行此命令:

php artisan passport:client --password

請求令牌

創(chuàng)建密碼授權的客戶端后,就可以使用用戶的電子郵件地址和密碼向 /oauth/token 路由發(fā)出 POST 請求來獲取訪問令牌。而該路由已經(jīng)由 Passport::routes 方法注冊,因此不需要手動定義它。如果請求成功,會在服務端返回的 JSON 響應中收到一個 access_tokenrefresh_token

$http = new GuzzleHttp\Client;
$response = $http->post('http://your-app.com/oauth/token', [
    'form_params' => [   
         'grant_type' => 'password',        
         'client_id' => 'client-id',        
         'client_secret' => 'client-secret',        
         'username' => 'taylor@laravel.com',        
         'password' => 'my-password',        
         'scope' => '',    
         ],]);
   return json_decode((string) $response->getBody(), true);

{tip} 默認情況下,訪問令牌是長期有效的。你可以根據(jù)需要 配置訪問令牌的有效時間

請求所有作用域

使用密碼授權機制時,可以通過請求 scope 參數(shù) * 來授權應用程序支持的所有范圍的令牌。如果你的請求中包含 scope 為 * 的參數(shù),令牌實例上的 can 方法會始終返回 true。這種作用域的授權只能分配給使用 password 授權時發(fā)出的令牌:

$response = $http->post('http://your-app.com/oauth/token', [
    'form_params' => [   
         'grant_type' => 'password',        
         'client_id' => 'client-id',        
         'client_secret' => 'client-secret',        
         'username' => 'taylor@laravel.com',        
         'password' => 'my-password',        
         'scope' => '*',
        ],
      ]);

自定義用戶名字段

當使用密碼授權時,Passport 默認使用 email 作為「用戶名」。但是,你可以通過在模型上定義一個 findForPassport 方法來自定義用戶名字段:

<?php
    namespace App;
    use Laravel\Passport\HasApiTokens;
    use Illuminate\Notifications\Notifiable;
    use Illuminate\Foundation\Auth\User as Authenticatable;
    class User extends Authenticatable{  
      use HasApiTokens, Notifiable;    
      /**
     * 通過用戶名找到對應的用戶信息
     *
     * @param  string  $username
     * @return \App\User
     */   
      public function findForPassport($username) 
         {    
             return $this->where('username', $username)->first(); 
         }
      }

隱式授權令牌

隱式授權類似于授權碼授權,但是它只將令牌返回給客戶端而不交換授權碼。這種授權最常用于無法安全存儲客戶端憑據(jù)的 JavaScript 或移動應用程序。通過調用 AuthServiceProvider 中的 enableImplicitGrant 方法來啟用這種授權:

/**
 * 注冊認證 / 授權服務
 *
 * @return void
 */
 public function boot(){
     $this->registerPolicies();    
     Passport::routes();    
     Passport::enableImplicitGrant();
    }

調用上面方法開啟授權后,開發(fā)者可以使用他們的客戶端 ID 從應用程序請求訪問令牌。接入的應用程序應該向你的應用程序的 /oauth/authorize 路由發(fā)出重定向請求,如下所示:

Route::get('/redirect', function () {
    $query = http_build_query([   
         'client_id' => 'client-id',        
         'redirect_uri' => 'http://example.com/callback',        
         'response_type' => 'token',        
         'scope' => '',    
         ]);    
    return redirect('http://your-app.com/oauth/authorize?'.$query);
  });

{tip} 注意,/oauth/authorize 路由已經(jīng)在 Passport::routes 方法中定義好,所以無需再次手動定義此路由。

客戶端憑據(jù)授權令牌

客戶端憑據(jù)授權適用于機器到機器的認證。例如,你可以在通過 API 執(zhí)行維護任務中使用此授權。

在客戶端憑據(jù)授權之前,需要先創(chuàng)建一個客戶端憑據(jù)授權的客戶端,你可以使用 passport:client 命令的 --client 參數(shù)來創(chuàng)建:

php artisan passport:client --client

接下來,要使用這種授權,你首先需要在 app/Http/Kernel.php$routeMiddleware 變量中添加新的中間件:

use Laravel\Passport\Http\Middleware\CheckClientCredentials;
protected $routeMiddleware = [
    'client' => CheckClientCredentials::class,
  ];

然后,在路由上追加這個中間件:

Route::get('/orders', function (Request $request) {
    ...
 })->middleware('client');

若要將對路由的訪問限制在某個作用域內,可在將 client 中間件附加到路由時提供以逗號分隔的所需作用域列表:

Route::get('/orders', function (Request $request) {
    ...
})->middleware('client:check-status,your-scope');

獲取令牌

通過向 oauth/token 接口發(fā)出請求來獲取令牌:

$guzzle = new GuzzleHttp\Client;
$response = $guzzle->post('http://your-app.com/oauth/token', [ 
   'form_params' => [ 
          'grant_type' => 'client_credentials',        
          'client_id' => 'client-id',        
          'client_secret' => 'client-secret',        
          'scope' => 'your-scope',    
         ],]);
   return json_decode((string) $response->getBody(), true)['access_token'];

個人訪問令牌

有時候,用戶要在不經(jīng)過傳統(tǒng)的授權碼重定向流程的情況下向自己發(fā)出訪問令牌。允許用戶通過應用程序用戶界面對自己發(fā)出令牌,有助于用戶體驗你的 API,或者也可以將其作為一種更簡單的發(fā)布訪問令牌的方式。

{note} 個人訪問令牌是永久有效的,就算使用了 tokensExpireInrefreshTokensExpireIn 方法也不會修改它的生命周期。

創(chuàng)建個人訪問客戶端

在你的應用程序發(fā)布個人訪問令牌之前,你需要在 passport:client 命令后帶上 --personal 參數(shù)來創(chuàng)建對應的客戶端。如果你已經(jīng)運行了 passport:install 命令,則無需再運行此命令:

php artisan passport:client --personal

如果你已經(jīng)創(chuàng)建了個人訪問客戶端,你可以通過調用 AuthServiceProvider 中的 personalAccessClientId 方法來啟用:

/**
 * 注冊認證 / 授權服務
 *
 * @return void
 */
 public function boot(){ 
    $this->registerPolicies();    
    Passport::routes();    
    Passport::personalAccessClientId('client-id');
  }

管理個人訪問令牌

創(chuàng)建個人訪問客戶端后,你可以使用 User 模型實例上的 createToken 方法來為給定用戶發(fā)布令牌。createToken 方法接受令牌的名稱作為其第一個參數(shù)和可選的 作用域 數(shù)組作為其第二個參數(shù):

$user = App\User::find(1);
// 創(chuàng)建沒有作用域的訪問令牌...
$token = $user->createToken('Token Name')->accessToken;
// 創(chuàng)建有作用域的訪問令牌...
$token = $user->createToken('My Token', ['place-orders'])->accessToken;

JSON API

Passport 中也有用來管理個人訪問令牌的 JSON API,你可以將其與自己的前端配對,為用戶提供管理個人訪問令牌的儀表板。下面我們會介紹用于管理個人訪問令牌的所有 API 接口。方便起見,我們使用  Axios 來演示對 API 的接口發(fā)出 HTTP 請求。

JSON API 由 webauth 中間件保護;因此,只能從您自己的應用程序中調用它。無法從外部源調用它。

{tip} 如果你不想實現(xiàn)自己的個人訪問令牌管理的前端界面,可以根據(jù)  前端快速上手 在幾分鐘內組建功能齊全的前端界面。

GET /oauth/scopes

此路由會返回應用程序中定義的所有 作用域。你可以使用此路由列出用戶可能分配給個人訪問令牌的范圍:

axios.get('/oauth/scopes')
    .then(response => {
        console.log(response.data);    
      });

GET /oauth/personal-access-tokens

此路由返回認證用戶創(chuàng)建的所有個人訪問令牌。這主要用于列出所有用戶的令牌,以便他們可以編輯或刪除它們:

axios.get('/oauth/personal-access-tokens')
    .then(response => {
        console.log(response.data);   
      });

POST /oauth/personal-access-tokens

此路由用于創(chuàng)建新的個人訪問令牌。它需要兩個數(shù)據(jù):令牌的 namescpoe

const data = {
    name: 'Token Name',
    scopes: []};
    axios.post('/oauth/personal-access-tokens', data)
        .then(response => {
            console.log(response.data.accessToken);    
        })    
        .catch (response => { 
               // 列出響應中錯誤...    
        });

DELETE /oauth/personal-access-tokens/{token-id}

此路由可用于刪除個人訪問令牌:

axios.delete('/oauth/personal-access-tokens/' + tokenId);

路由保護

通過中間件

Passport 包含一個 驗證保護機制 可以驗證請求中傳入的訪問令牌。配置 api 的看守器使用 passport 驅動程序后,只需要在需要有效訪問令牌的任何路由上指定 auth:api 中間件:

Route::get('/user', function () {
    //
 })->middleware('auth:api');

傳遞訪問令牌

當調用 Passport 保護下的路由時,接入的 API 應用需要將訪問令牌作為 Bearer 令牌放在請求頭 Authorization 中。例如,使用 Guzzle HTTP 庫時:

$response = $client->request('GET', '/api/user', [
    'headers' => [  
          'Accept' => 'application/json',        
          'Authorization' => 'Bearer '.$accessToken,    
         ],
      ]);

令牌作用域

作用域可以讓 API 客戶端在請求賬戶授權時請求特定的權限。例如,如果你正在構建電子商務應用程序,并不是所有接入的 API 應用都需要下訂單的功能。你可以讓接入的 API 應用只被允許授權訪問訂單發(fā)貨狀態(tài)。換句話說,作用域允許應用程序的用戶限制第三方應用程序執(zhí)行的操作。

定義作用域

你可以在 AuthServiceProviderboot 方法中使用 Passport::tokensCan 方法來定義 API 的作用域。tokensCan 方法接受一個包含作用域名稱和描述的數(shù)組作為參數(shù)。作用域描述將會在授權確認頁中直接展示給用戶,你可以將其定義為任何你需要的內容:

use Laravel\Passport\Passport;
Passport::tokensCan([
    'place-orders' => 'Place orders',    
    'check-status' => 'Check order status',
  ]);

默認作用域

如果客戶端沒有請求任何特定的范圍,你可以在 AuthServiceProviderboot 方法中使用 Passport::setDefaultScope 方法來定義默認的作用域。

use Laravel\Passport\Passport;Passport::setDefaultScope([
    'check-status',    
    'place-orders',
  ]);

給令牌分配作用域

請求授權碼

使用授權碼請求訪問令牌時,接入的應用需為 scope 參數(shù)指定所需作用域。 scope 參數(shù)包含多個作用域時,名稱之間使用空格分割:

Route::get('/redirect', function () {
    $query = http_build_query([  
          'client_id' => 'client-id',        
          'redirect_uri' => 'http://example.com/callback',        
          'response_type' => 'code',        
          'scope' => 'place-orders check-status',   
        ]);    
 return redirect('http://your-app.com/oauth/authorize?'.$query);});

分發(fā)個人訪問令牌

使用 User 模型的 createToken 方法發(fā)放個人訪問令牌時,可以將所需作用域的數(shù)組作為第二個參數(shù)傳給此方法:

$token = $user->createToken('My Token', ['place-orders'])->accessToken;

檢查作用域

Passport 包含兩個中間件,可用于驗證傳入的請求是否包含訪問指定作用域的令牌。 使用之前,需要將下面的中間件添加到 app/Http/Kernel.php 文件的 $routeMiddleware 屬性中:

'scopes' => \Laravel\Passport\Http\Middleware\CheckScopes::class,
'scope' => \Laravel\Passport\Http\Middleware\CheckForAnyScope::class,

檢查所有作用域

路由可以使用 scopes 中間件來檢查當前請求是否擁有指定的 所有 作用域:

Route::get('/orders', function () { 
   // Access token has both "check-status" and "place-orders" scopes...
   })->middleware('scopes:check-status,place-orders');

檢查任意作用域

路由可以使用 scope 中間件來檢查當前請求是否擁有指定的 任意 作用域:

Route::get('/orders', function () {
    // 訪問令牌具有 "check-status" 或 "place-orders" 作用域...
  })->middleware('scope:check-status,place-orders');

檢查令牌實例上的作用域

就算含有訪問令牌驗證的請求已經(jīng)通過應用程序的驗證,你仍然可以使用當前授權 User 實例上的 tokenCan 方法來驗證令牌是否擁有指定的作用域:

use Illuminate\Http\Request;
Route::get('/orders', function (Request $request) {
    if ($request->user()->tokenCan('place-orders')) { 
           //    
         }
     });

附加作用域方法

scopeIds 方法將返回所有已定義 ID / 名稱的數(shù)組:

Laravel\Passport\Passport::scopeIds();

scopes 方法將返回一個 包含所有已定義作用域數(shù)組的 Laravel\Passport\Scope 實例:

Laravel\Passport\Passport::scopes();

scopesFor 方法將返回與給定 ID / 名稱匹配的 Laravel\Passport\Scope 實例數(shù)組:

Laravel\Passport\Passport::scopesFor(['place-orders', 'check-status']);

你可以使用 hasScope 方法確定是否已定義給定作用域:

Laravel\Passport\Passport::hasScope('place-orders');

使用 JavaScript 接入 API

在構建 API 時, 如果能通過 JavaScript 應用接入自己的 API 將會給開發(fā)過程帶來極大的便利。這種 API 開發(fā)方法允許你使用自己的應用程序的 API 和別人共享的 API 。你的 Web 應用程序、移動應用程序、第三方應用程序以及可能在各種軟件包管理器上發(fā)布的任何 SDK 都可能會使用相同的 API 。

通常,如果要在 JavaScript 應用程序中使用 API ,需要手動向應用程序發(fā)送訪問令牌,并將其傳遞給應用程序。但是, Passport 有一個可以處理這個問題的中間件。將 CreateFreshApiToken 中間件添加到 app/Http/Kernel.php 文件中的 web 中間件組就可以了:

'web' => [ 
   // 其他中間件...
    \Laravel\Passport\Http\Middleware\CreateFreshApiToken::class,
   ],

{note} 你應該確保在您的中間件堆棧中 CreateFreshApiToken 中間件之前列出了 EncryptCookies 中間件。

這個 Passport 中間件將在你所有的對外請求中添加一個 laravel_token cookie 。該 cookie 將包含一個加密后的 JWT , Passport 將用來驗證來自 JavaScript 應用程序的 API 請求。至此,你可以在不明確傳遞訪問令牌的情況下向應用程序的 API 發(fā)出請求:

axios.get('/api/user')
    .then(response => {
        console.log(response.data);    
     });

自定義 Cookie 名稱

如果需要,你可以在 AuthServiceProviderboot 方法中使用 Passport::cookie 方法來自定義 laravel_token cookie 的名稱。

/**
 * 注冊認證 / 授權服務
 *
 * @return void
 */
 public function boot(){
     $this->registerPolicies();    
     Passport::routes();    
     Passport::cookie('custom_name');
   }

CSRF 保護

當使用這種授權方法時,默認的 Laravel JavaScript 腳手架會讓 Axios 發(fā)送 X-CSRF-TOKENX-Requested-With 請求頭。另外,你必須確保 HTML meta 標簽 標簽 中包含了 CSRF 令牌:

// In your application layout...
<meta name="csrf-token" content="{{ csrf_token() }}">
// Laravel's JavaScript scaffolding...
window.axios.defaults.headers.common = {
    'X-Requested-With': 'XMLHttpRequest',
   };

事件

Passport 在發(fā)出訪問令牌和刷新令牌時觸發(fā)事件。你可以在應用程序 的 EventServiceProvider 中為這些事件追加監(jiān)聽器,并在監(jiān)聽器中撤銷或修改其他令牌:

/**
 * 應用程序事件監(jiān)聽映射
 *
 * @var array
 */
 protected $listen = [
     'Laravel\Passport\Events\AccessTokenCreated' => [
             'App\Listeners\RevokeOldTokens', 
               ],    
      'Laravel\Passport\Events\RefreshTokenCreated' => [ 
             'App\Listeners\PruneOldTokens',   
             ],
         ];

測試

Passport 的 actingAs 方法可以指定當前已認證用戶及其作用域。actingAs 方法的第一個參數(shù)是用戶實例,第二個參數(shù)是用戶令牌作用域數(shù)組:

use App\User;
use Laravel\Passport\Passport;
public function testServerCreation(){
    Passport::actingAs(  
          factory(User::class)->create(),   
               ['create-servers']  
             );    
         $response = $this->post('/api/create-server');    
        $response->assertStatus(201);
     }
本文章首發(fā)在 LearnKu.com 網(wǎng)站上。