Edited at

Laravel5.5でAPI認証のパッケージ(Laravel Passport)を利用する

More than 1 year has passed since last update.


  • Laravel Passportの動作をmacOSで確認したメモ


環境


macOS Sierra


APIサーバー


  • Vagrant

  • VirtualBox

  • Laravel5.5

https://github.com/niiyz/Laravel-API-Auth-Sample


クライアントサーバー


  • MacのPHPビルトインサーバー

https://github.com/niiyz/Laravel-API-Auth-Client-Server-Sample


MacのPHPバージョンを7.0にする


  • Laravel5.5はPHP7.0以上が必須


brewを使用してPHP7インストール

brew update

brew install homebrew/php/php70


パス設定


  • シェルの設定に追記後、反映

vi ~/.zshrc

export PATH="$(brew --prefix homebrew/php/php70)/bin:$PATH" <-1行追記する
source ~/.zshrc


確認


  • PHP7.0を確認

php -v                                                                                   

PHP 7.0.22 (cli) (built: Aug 7 2017 14:07:27) ( NTS )
Copyright (c) 1997-2017 The PHP Group
Zend Engine v3.0.0, Copyright (c) 1998-2017 Zend Technologies


APIサーバー(Laravel5.5)


Laravel5.5インストール

composer create-project --prefer-dist laravel/laravel Laravel-API-Auth-Sample dev-develop


プロジェクト直下にHomesteadインストール(vagrant)

composer require laravel/homestead --dev

php vendor/bin/homestead make


  • 起動

vagrant up


  • SSH接続

vagrant ssh


ユーザー認証(通常のユーザー作成準備)


  • ユーザーテーブルSeeder作成

php artisan make:seeder UsersTableSeeder


データ追加処理


  • ユーザーテーブルSeeder追記


database/seeds/UsersTableSeeder.php

<?php

use Illuminate\Database\Seeder;
use App\User;

class UsersTableSeeder extends Seeder
{
/**
* Run the database seeds.
*
* @return void
*/

public function run()
{
factory(User::class)->create([
'name' => 'テスト',
'email' => 'test@example.com'
]);
}
}



  • DatabaseSeeder.phpのコメント解除


database/seeds/DatabaseSeeder.php

// コメントアウト

$this->call(UsersTableSeeder::class);


ログイン機能追加


  • ログイン画面用のリソースなどが追加される

php artisan make:auth


API認証


passportインストール

composer require laravel/passport


Provider追記

Laravel PassportパッケージはPackage Auto-Discoveryに対応しているためインストールした際に自動でサービスプロバイダに追加されるのでconfig/app.php記述する儀式が不要になったようです。


config/app.php

/*

* Package Service Providers...
*/

// Laravel\Passport\PassportServiceProvider::class, // 1行追記

/*
* Application Service Providers...
*/



DB初期化

php artisan migrate


  • UserSeederに記述したユーザーがusersテーブルに作成される

id         1

name テスト
email test@example.com
password secret


  • OAuth用のテーブルが作成される

oauth_auth_codes

oauth_clients
oauth_personal_acces_clients
oauth_refresh_tokens


OAuth認証のユーザーを作成する


  • 「user ID」 はusers.id を指定する

  • callback用のURLを指定

  • 「Client ID」,「Client secret」がoauth_clientsテーブルに追加される

$ php artisan passport:client


Which user ID should the client be assigned to?:
> 1

What should we name the client?:
> test

Where should we redirect the request after authorization? [http://localhost/auth/callback]:
> http://localhost:3333/callback.php

New client created successfully.
Client ID: 1
Client secret: cZ9W9ysdUFKlowO5d2CzzFFJ1uOBfggjv5Jx5cwr


クライアントサーバー(Macビルドインサーバー)


認証画面を通すやり方


  • よくあるtwitterのアカウントで別サービスにログインする感じのやつ


oAuthサバーへアクセスする


get_token.php

<?php

require 'vendor/autoload.php';

use GuzzleHttp\Client as Client;

$guzzle = new Client;

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

header('Location: http://192.168.10.10/oauth/authorize?' . $query);



承認画面

スクリーンショット 2017-09-05 20.23.51.png


  • 「Authorize」ボタンを押下するとcodeパラメータ付きでコールバックURLに戻る

  • 「Cancel」ボタン押下するとerrorパラメータ付きでコールバックURLに戻る

  • 承認するとoauth_access_tokens, oauth_auth_codesテーブルにデータが格納される


コールバック


get_token_callback.php

<?php 

require 'vendor/autoload.php';

use GuzzleHttp\Client as Client;

$http = new Client;

if ($_GET['code']) {
$response = $http->post('http://192.168.10.10/oauth/token', [
'form_params' => [
'grant_type' => 'authorization_code',
'client_id' => '1',
'client_secret' => 'cZ9W9ysdUFKlowO5d2CzzFFJ1uOBfggjv5Jx5cwr',
'redirect_uri' => 'http://localhost:3333/callback.php',
'code' => $_GET['code'],
],
]);
var_dump(json_decode((string)$response->getBody(), true));
}



出力結果


  • 取得したaccess_tokenを使って外部API認証に使う

array(4) {

["token_type"]=>
string(6) "Bearer"
["expires_in"]=>
int(1296000)
["access_token"]=>
string(1071) "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImp0aSI6ImYxMmE0NDZkNmQxZjBlNzA4MWMwZWEwMzg5MDkxOWI1NWEzYzE5YTMxMGRlMGYwOWQ0ZjA4MmMzYTcxNGU1MzhmOGMzZTk3MzllZTc3OWQ1In0.eyJhdWQiOiIxIiwianRpIjoiZjEyYTQ0NmQ2ZDFmMGU3MDgxYzBlYTAzODkwOTE5YjU1YTNjMTlhMzEwZGUwZjA5ZDRmMDgyYzNhNzE0ZTUzOGY4YzNlOTczOWVlNzc5ZDUiLCJpYXQiOjE1MDQ2MDg2NTcsIm5iZiI6MTUwNDYwODY1NywiZXhwIjoxNTA1OTA0NjU3LCJzdWIiOiIxIiwic2NvcGVzIjpbXX0.kbvE4yrfGXcI4Bg0VW10-sDlFpsiG-_UB4uRIi_ylpB46kUkto3JdmlfWLINM83RWNrSkBdnzq6IYfPiHZY1wOw6qwObKG97pWhQVZO9yizVlZCe-ejRO-xv4do0QbXZQHzQqACwhSAYdQwymEJr3JqjrcaNUU8UV5wftlfLsDYNp-NVdo9hvq_7o49B79tIGG7F2izj0mmDHKXfhWLg5s8rFgkHw1q-Wn6o-YCMHgQhfWR9IVvJJ9bpywe45gcvse-MqaaFIQL4q-PHcSLAP0JHMrWLTHy0S2O-D10nWNE2XJyh3VPnxnKLH2jrGZpQVRpUN6RNQlftCxVJEoPruhyeE0Emb5KNJkwvFeIn2hEmLIseXqD4kuk0VESNlCz3VD0r6HRtvfpCTbHBK2uj_l69oYV0yUC6r_D-BfBK6ATZdTk-RIk3HV41ksMqOfpuSPymLoAieq_WqmU0i93VoACwoycirP6z1JTMuT4E1z8i_etgiodcOGpRWZQrePACURCxxGk1xGCaSRMVF_c42WNC5cw10wcHld9FToeFD4-KT_nBryz_eOMJ9Iw6foiyusRbR0vriGExOAesSiLpgLwnDEFBh3YpsDiOEVPvMJolMlVQ6tOnaUwyC3qunjrjVlbF9YR40r1b9DVJ7ZhhWGJNgYg0qadbNGt2uLIYscU"
["refresh_token"]=>
string(706) "def50200ce6524158569f59de11fd955552ae132336954dbd53dffc22544a3af145d1cc0b2b78c36b3c65c238c1486f24b3b551061591a84ec92d68d4438c62de3e6bcffa0df6ce1fa7ea127078a107390b8d3023897eff6cef63064e39b9376ab4ae4e685cc5b9b6b3ed67efe312de73c06458b78c6e7b8e6719d4e11cc9e57315ebb36b0b5e869ac9c0a8ae5f973e12ae2d26f61192d0532c7aeff90e6b7802fc6bd78a7303583bee7f14fabf31486e6431320e6f3d206c61af9dfb482b8195fb0577e9f5cefeb765742400aec2f3f9e16d3b70c5d21732347190bae5287cd13ad01f0b42e1cd3cfc51c193bfce2ffcb5b06f75224c1a7c6498657d2320fd44a78bc047b9bf2bdd17654b69ce9c74280d42bab8be6619be419ee84700d7086ff638a9b715290286906274bccbe9b876afb1b83382b2b2c9840423210e3b5ca4c9cab938391844e261ca6b247e88b3bc96b18d505784c87ef6932c1ed9dec7cc8"
}


認証画面なしでパスワード付きで外部からAPIを実行する


  • 認証画面なしで外部からAPIを通してデータを保存したかったのでパスワード付きの認証にする


OAuth認証のユーザーを作成(APIサーバー)


  • パスワードオプション付きでOAuthユーザー作成

  • usersテーブルのidとは紐付けなくても良いみたい

# php artisan passport:client --password --name=password-user

Password grant client created successfully.
Client ID: 6
Client Secret: IzRQarKQ5y7b8Ni4Sf4nBvlDxeDAujm10lH6r3OW


API作成(APIサーバー)


  • 外部からアクセスしてデータを保存するAPI


routes/api.php

Route::middleware('auth:api')->get('/memo', function (Request $request) {

$memo = $request->get('memo');

// SAVE MEMO...

return json_encode(array_merge(['status' => 'OK'], ['memo' => $memo . '-saved']));
});



クライアントサーバー(Macビルドインサーバー)


  • OAuthユーザーのID, Secretを使用する

  • 併せて通常のLaravelログインユーザーのID, Passwordも使用する


password_auth.php

<?php

require 'vendor/autoload.php';

use GuzzleHttp\Client as Client;

/**
* Class APIClient
*/

class APIClient {

/**
* @var Client
*/

protected $http;

/**
* @var
*/

protected $accessToken;

/**
*
*/

const API_SERVER = 'http://192.168.10.10';

/**
* APIClient constructor.
*/

public function __construct()
{
$this->http = new Client;
}

/**
* @param array $config
*/

public function auth(array $config = [])
{

$response = $this->http->post(self::API_SERVER . '/oauth/token', [
'form_params' => [
'grant_type' => 'password',
'client_id' => $config['client_id'],
'client_secret' => $config['client_secret'],
'username' => $config['username'],
'password' => $config['password'],
'scope' => '',
],
]);

$body = json_decode((string)$response->getBody(), true);

$this->accessToken = $body['access_token'];

}

/**
* @param string $memo
*/

public function save(string $memo = '')
{

$response = $this->http->request('GET', self::API_SERVER . '/api/memo', [
'headers' => [
'Accept' => 'application/json',
'Authorization' => 'Bearer '. $this->accessToken,
],
'query' => ['memo' => $memo],
]);

$body = json_decode((string)$response->getBody(), true);

if (isset($body['status']) && $body['status'] === 'OK') {
var_dump('saved memo');
}
}
}

// write .env etc
$config = [
'client_id' => '6',
'client_secret' => 'IzRQarKQ5y7b8Ni4Sf4nBvlDxeDAujm10lH6r3OW',
'username' => 'test@example.com',
'password' => 'secret',
];

$client = new APIClient;

$client->auth($config);
$client->save('ほげ');
// string(10) "saved memo" array(2) { ["status"]=> string(2) "OK" ["memo"]=> string(12) "ほげ-saved" }



参照

https://github.com/laravel/passport

https://laravel.com/docs/5.5/authentication#authenticating-users

https://laravel.com/docs/master/passport#introduction