在 Laravel 5.7 使用 Passport 實作 API 認證

環境

  • Windows 10
  • Homestead

建立專案

1
laravel new passport

安裝套件

1
composer require laravel/passport

執行遷移

1
php artisan migrate

新增填充

新增 UsersTableSeeder 填充。

1
php artisan make:seed UsersTableSeeder

UsersTableSeeder.php 檔新增一名測試用使用者資訊。

1
2
3
4
5
6
7
8
public function run()
{
App\User::create([
'name' => 'Test User',
'email' => 'homestead@test.com',
'password' => bcrypt('secret'),
]);
}

執行填充。

1
php artisan db:seed

生成密鑰

執行安裝。

1
php artisan passport:install

得到以下資訊。

1
2
3
4
5
6
Personal access client created successfully.
Client ID: 1
Client Secret: AHB4p……tdffF
Password grant client created successfully.
Client ID: 2
Client Secret: 28ch1……ioMe7

若只有密碼授權,執行:

1
php artisan passport:client --password

若只有客戶端憑證授權,執行:

1
php artisan passport:client --client

修改模型

修改 User 模型。

1
2
3
4
5
6
7
8
9
10
namespace App;

use Laravel\Passport\HasApiTokens;
use Illuminate\Notifications\Notifiable;
use Illuminate\Foundation\Auth\User as Authenticatable;

class User extends Authenticatable
{
use HasApiTokens, Notifiable;
}

註冊路由

app\Providers\AuthServiceProvider.php 檔註冊路由。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
namespace App\Providers;

use Laravel\Passport\Passport;
use Illuminate\Support\Facades\Gate;
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;

class AuthServiceProvider extends ServiceProvider
{
/**
* The policy mappings for the application.
*
* @var array
*/
protected $policies = [
'App\Model' => 'App\Policies\ModelPolicy',
];

/**
* Register any authentication / authorization services.
*
* @return void
*/
public function boot()
{
$this->registerPolicies();

Passport::routes(function ($router) {
$router->forAccessTokens();
});

Passport::tokensExpireIn(now()->addMinutes(360)); // Token 有效時間
Passport::refreshTokensExpireIn(now()->addDays(7)); // Refresh Token 有效時間
}
}

修改認證設定

修改 config/auth.php 檔。

1
2
3
4
5
6
7
8
9
10
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],

'api' => [
'driver' => 'passport', // 改成 passport
'provider' => 'users',
],

發起 HTTP 請求

http://passport.test/api/user 發起 GET 請求,得到回應如下:

1
[MethodNotAllowedHttpException] No message

Accept 輸入 application/json 可以得到以下回應:

1
2
3
{
"message": "Unauthenticated."
}

客戶端憑證授權

app/Http/Kernel.phprouteMiddleware 新增中介層。

1
2
3
4
protected $routeMiddleware = [
// ...
'client' => \Laravel\Passport\Http\Middleware\CheckClientCredentials::class,
];

修改路由。

1
2
3
Route::get('/user', function (Request $request) {
return \App\User::get();
})->middleware('client');

http://passport.test/oauth/token 發起 POST 請求:

1
2
3
4
5
{
"grant_type": "client_credentials",
"client_id" : 2,
"client_secret": "28ch1……ioMe7"
}

得到回應如下:

1
2
3
4
5
{
"token_type": "Bearer",
"expires_in": 599,
"access_token": "eyJ0e……uAqSw"
}

最後在 Headers 輸入以下鍵値,再向 http://passport.test/api/user 發起 GET 請求。

Key Value
Authorization Bearer eyJ0e……uAqSw
  • Value 的部分為:Bearer + 空一格 + Token。

結果得到回應如下:

1
2
3
4
5
6
7
8
9
10
[
{
"id": 1,
"name": "Test User",
"email": "homestead@test.com",
"email_verified_at": null,
"created_at": "2018-11-03 16:27:33",
"updated_at": "2018-11-03 16:27:33"
}
]

密碼授權

使用預設路由。

1
2
3
Route::middleware('auth:api')->get('/user', function (Request $request) {
return $request->user();
});

http://passport.test/oauth/token 發起 POST 請求:

1
2
3
4
5
6
7
{
"grant_type": "password",
"client_id" : 2,
"client_secret": "28ch1……ioMe7",
"username": "homestead@test.com",
"password": "secret"
}

得到回應如下:

1
2
3
4
5
6
{
"token_type": "Bearer",
"expires_in": 599,
"access_token": "eyJ0e……uAqSw",
"refresh_token": "def50……29a13"
}

最後在 Headers 輸入以下鍵値,再向 http://passport.test/api/user 發起 GET 請求。

Key Value
Authorization Bearer def50……29a13
  • Value 的部分為:Bearer + 空一格 + Token。

結果得到回應如下:

1
2
3
4
5
6
7
8
9
10
[
{
"id": 1,
"name": "Test User",
"email": "homestead@test.com",
"email_verified_at": null,
"created_at": "2018-11-03 16:27:33",
"updated_at": "2018-11-03 16:27:33"
}
]

如果要刷新 Token,則向 http://passport.test/oauth/token 發起 POST 請求:

1
2
3
4
5
6
{
"grant_type": "refresh_token",
"client_id" : 2,
"client_secret": "28ch1……ioMe7",
"refresh_token": "def50……29a13"
}

得到回應如下:

1
2
3
4
5
6
{
"token_type": "Bearer",
"expires_in": 599,
"access_token": "eyJ0e……sLOaA",
"refresh_token": "def50……9d38c"
}

部署

部署到正式環境時,需要產生 Passport 金鑰。

1
php artisan passport:keys

程式碼

參考資料