Slide 1

Slide 1 text

【今夜勝ちたい】 LaravelでAPI認証カスタマイズ 【シューマイ】Tech Lead Engineerから最新技術を学べ! Laravel編 2019.08.07 株式会社プラムザ 志村和彦

Slide 2

Slide 2 text

自己紹介 志村 和彦(Shimura Kazuhiko) 所属:株式会社プラムザ    PrimeOrder事業部 AWSとかちょっとできる。 VBもちょっとできる。 スマスピで遊ぼうと企んでいる。 2

Slide 3

Slide 3 text

“ 今回は 「デフォルトで用意されているAPI のToken認証をカスタマイズして みよう」 という話です。 3

Slide 4

Slide 4 text

4 model (テーブル) Provider Request Guard ① 認証情報を取得 大体の認証の流れ アプリ本体 ② 照合 ③ 被認証者情報 &Requestがアプリへ

Slide 5

Slide 5 text

カスタマイズ イズ どこ? 参照テーブル TokenGuardを使用 したトークン認証にて 参照するテーブルを カスタマイズします。 参照カラム 照合するカラム名をカ スタマイズします。 認証条件 トークンの一致以外 に、認証に必要な条 件をカスタマイズしま す。 5 デフォルトのToken認証は下記を使用 Guard: TokenGuard Provider: users 「トークンとusersテーブルのapi_tokenカラムを照合する」設定

Slide 6

Slide 6 text

参照テーブル え?user?もうトークン格納用のテーブル定義し ちゃったよ? 1

Slide 7

Slide 7 text

7 Model A(テーブル A) Provider A 参照先 イズ どこ? Model B(テーブル B) Provider B 【参照先】 Providerとセットで、 config/auth.phpにて管理 例) デフォルトのProviderであるusersは、 App\User(に紐づくテーブル) 参照先を変更する方法は以下 1. Modelの参照テーブルを変更 2. セットになるModelを変更 3. 新たにセットを作成して使用

Slide 8

Slide 8 text

config/auth.phpを修正 8 'guards' => [ 'api' => [ 'driver' => 'token', // TokenGuardが使用される // 'provider' => 'users', 'provider' => 'access_tokens', // 使用するproviderを指定 'hash' => false, ], ], 'providers' => [ // デフォルトで設定されているProvider 'users' => [ 'driver' => 'eloquent', ‘model' => App\User::class, ], // providerに指定した名前で追加 'access_tokens' => [ 'driver' => 'eloquent', 'model' => App\AccessToken::class, // 指定したModelに対応したtableが参照される ], ],

Slide 9

Slide 9 text

ちなみに 9 # App/AccessToken.php

Slide 10

Slide 10 text

参照カラム api_token・・・ access_tokenって名前にしちゃったよ 2

Slide 11

Slide 11 text

参照カラム イズ どこ 11 # config/auth.php 'guards' => [ 'api' => [ 'driver' => 'token', // ここで指定するものを実装する // 'provider' => 'users', 'provider' => 'access_tokens', // 使用するproviderを指定 'hash' => false, ], ], Requestからトークンの取得するのは Guardの役目になります。 トークンの取得方法は Guard毎に定義されるため、 参照するカラムを変更するには TokenGuardの代わりとなる 独自Guardを実装する必要があります。 Request Guard トークンを取得

Slide 12

Slide 12 text

TokenGuard イズ なに? 12 # vendor/laravel/framework/src/Illuminate/Auth/TokenGuard.php public function __construct( UserProvider $provider, Request $request, $inputKey = 'api_token', // 取得キー名 ここ変えたい! $storageKey = 'api_token', // 参照キー名 ここ変えたい! $hash = false) { $this->hash = $hash; $this->request = $request; $this->provider = $provider; $this->inputKey = $inputKey; $this->storageKey = $storageKey; } ・トークン取得元、参照キー名などを定義し、リクエストからトークンを取得 ・providerを介して指定モデル(テーブル)、条件でトークン該当データを照合 public function getTokenForRequest() { $token = $this->request->query($this->inputKey); if (empty($token)) { $token = $this->request->input($this->inputKey); } if (empty($token)) { $token = $this->request->bearerToken(); } if (empty($token)) { $token = $this->request->getPassword(); } return $token; }

Slide 13

Slide 13 text

“ 訪問者(リクエスト)から鍵を受け 取って門の中のproviderに照 合を頼む。 まさにGuard(守衛) 13

Slide 14

Slide 14 text

独自Guard フロム TokenGuard 14 # app/Services/Auth/AccessTokenGuard.php use Illuminate\Auth\TokenGuard; use Illuminate\Contracts\Auth\UserProvider; use Illuminate\Http\Request; class AccessTokenGuard extends TokenGuard { public function __construct(UserProvider $provider, Request $request) { // 親(TokenGuard)のconstructのinputkey&storageKeyに参照させたいkey名を指定 parent::__construct($provider, $request, 'access_token', 'access_token'); } } TokenGuardを修正するわけにもいかないので extendして実装。 inputkey& storagekeyに参照させたいカラム名を指定

Slide 15

Slide 15 text

auth.phpで使えるようにする 15 # app/Providers/AuthServiceProvider.php registerPolicies(); Auth::extend('access_token', function ($app, $name, array $config) { return new AccessTokenGuard(Auth::createUserProvider($config['provider']), $app['request']); }); } } AuthServiceProvider内で”access_token”という名前でGuardを追加(Auth::extend)

Slide 16

Slide 16 text

auth.phpで設定 16 # onfig/auth.php 'guards' => [ 'api' => [ 'driver' => 'access_token', // 追加したaccess_tokenという名前のguardを指定 // 'provider' => 'users', 'provider' => 'access_tokens', // 使用するproviderを指定 'hash' => false, ], ], guards内のdriverに追加したGuardを設定することで、 参照カラムの変更が完了します。

Slide 17

Slide 17 text

認証条件 何・・・だと? 有効期限なんて、そんなのありかよ。 3

Slide 18

Slide 18 text

条件 イズ どこ 18 # config/auth.php 'providers' => [ 'users' => [ 'driver' => 'eloquent', 'model' => App\Models\User::class, ], 'access_tokens' => [ 'driver' => 'eloquent', // ここに指定するものを実装 'model' => App\Models\AccessToken::class, ], ], Guard側で指定するキー名は別として、 参照先での照合条件は Providerで定義されため、 認証条件を追加するには独自 Providerを実装する必要があります。 もともと指定されている eloquent(Illuminate\Auth\EloquentUserProvider)を拡張していきます。 model (テーブル) Provider トークンの照合はProviderの役目

Slide 19

Slide 19 text

EloquentUserProvider イズ なに? 19 # Illuminate\Auth\EloquentUserProvider public function retrieveByCredentials(array $credentials) { if (empty($credentials) || (count($credentials) === 1 && array_key_exists('password', $credentials))) { return; } $query = $this->newModelQuery(); ・Guardから渡された情報を元に認証関連操作(照合、取得、アップデート) ・照合結果をGaurdに渡す     foreach ($credentials as $key => $value) { if (Str::contains($key, 'password')) { continue; } if (is_array($value) || $value instanceof Arrayable) { $query->whereIn($key, $value); } else { $query->where($key, $value); } } return $query->first(); }

Slide 20

Slide 20 text

“ 守衛(Guard)から鍵を受け取っ て照合・データ提供を行う。 まさにProvider(提供者) 20

Slide 21

Slide 21 text

独自Provider フロム Eloquent 21 # app/Providers/AccessTokenProvider.php first(); } } TokenGuardと同様にextendして実装。retrieveByCredentialsに条件追加。

Slide 22

Slide 22 text

おまけ 22 AccessToken::validateExpire # app/AccessToken.php where('is_expired', false) ->where(function ($q) { $q->orWhere('expired_at', '>=', date("Y-m-d H:i:s")); $q->orWhereNull('expired_at'); }); }

Slide 23

Slide 23 text

auth.phpで使えるようにする 23 # app/Providers/AuthServiceProvider.php registerPolicies(); Auth::extend('access_token', function ($app, $name, array $config) { return new AccessTokenGuard(Auth::createUserProvider($config['provider']), $app['request']); });     Auth::provider('access_token', function ($app, array $config) { return new AccessTokenProvider($app['hash'], $config['model']); }); } } AuthServiceProvider内で”access_token”という名前でProviderを追加(Auth::provider)

Slide 24

Slide 24 text

auth.phpで設定 24 # onfig/auth.php 'providers' => [ 'users' => [ 'driver' => 'eloquent', 'model' => App\Models\User::class, ], 'access_tokens' => [ // 'driver' => 'eloquent', 'driver' => 'access_token', // 追加したaccess_tokenという名前のproviderを指定 'model' => App\Models\AccessToken::class, ], ], providers内のdriverに追加したProviderを設定することで、 認証条件の変更が完了します。

Slide 25

Slide 25 text

ざっくりまとめると 参照テーブル auth.phpのproviderの参照するモデルを書き換える 参照カラム Auth.phpのguards - driverに設定するguardを実装(TokenGuard extend) AuthServiceProvider.phpにて登録。auth.phpに設定。 認証条件 Auth.phpのprobiders - driverに設定するproviderを実装 (EloquentUserProvider extend) AuthServiceProvider.phpにて登録。auth.phpに設定。 25

Slide 26

Slide 26 text

“ カスタマイズをすることで ”各々が何をしているか” “どんなメソッドがあるのか” “なぜそんな動きをするのか” といった理解も深まります。 26

Slide 27

Slide 27 text

“ How (どうやるのか) & Why (なぜそうなるのか) 27

Slide 28

Slide 28 text

28 Thanks? 終わりのその前に

Slide 29

Slide 29 text

29 告知

Slide 30

Slide 30 text

30 Prime Order next stage

Slide 31

Slide 31 text

31 お客様の業務課題・業務フローを改善し、 お客様のビジネスに、 私たちのいる社会に、 新しい価値を生み出すことを目的とする。 それが Prime Order事業部です。 私たちはフリーランスエンジニアの方を募集しています。 Prime Order 参画者募集

Slide 32

Slide 32 text

32 ご興味をもっていただけた方 会社訪問のお申込みはこちらから https://goo.gl/forms/ICdr6QwE2mAjy7oM2

Slide 33

Slide 33 text

33 ご静聴ありがとうございました。 今度こそ本当に終わりです