どうもこんにちは。
Laravelばっかりです。
今回は、API認証です。
Laravel 5.8から、API認証のドキュメントがPassportを使わない方法になってます。
ちょっとお試しです。
ドキュメント ⇒ API認証 5.8 Laravel
目次
Migration
公式ドキュメントのとおりにやります。
■コマンド
php artisan make:migration prepare_users_table_for_api_token --table users
作成されたファイルを編集です。
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 35 |
<?php use Illuminate\Support\Facades\Schema; use Illuminate\Database\Schema\Blueprint; use Illuminate\Database\Migrations\Migration; class PrepareUsersTableForApiToken extends Migration { /** * Run the migrations. * * @return void */ public function up() { Schema::table('users', function (Blueprint $table) { $table->string('api_token', 80)->after('password') ->unique() ->nullable() ->default(null)->comment('API トークン'); }); } /** * Reverse the migrations. * * @return void */ public function down() { Schema::table('users', function (Blueprint $table) { $table->dropColumn('api_token'); }); } } |
あとはmigrate。
php artisan migrate
ここまでで準備完了です。
トークンの設定
今回、画面から要認証なAPIを使いたいので、トークン発行後Cookieに仕込みたいと思います。
とりあえず、画面アクセスのたびにCookieの有無を確認し、なければ発行する、
というような仕掛けにしようと思います。
■middleware
php artisan make:middleware GenerateApiToken
作成されたファイルを編集です。
ランダムな文字列を作って、Userモデル更新と同時にCookieに保存します。
Cookieの作り方は、CSRFトークンを作っているあたりを参考にしています。
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 35 36 37 38 39 40 41 42 43 44 45 |
<?php namespace App\Http\Middleware; use Carbon\Carbon; use Closure; use Illuminate\Support\Facades\Auth; use Illuminate\Support\Str; use Symfony\Component\HttpFoundation\Cookie; class GenerateApiToken { /** * Handle an incoming request. * * @param \Illuminate\Http\Request $request * @param \Closure $next * @return mixed */ public function handle($request, Closure $next) { $response = $next($request); $user = Auth::user(); if ($user) { if (!$request->cookie('api_token')) { $apiToken = Str::random(60); $user->update(['api_token' => $apiToken]); $response->headers->setCookie( new Cookie('api_token', $apiToken, Carbon::now()->addRealMinutes(config('session.lifetime'))->getTimestamp(), config('session.path'), config('session.domain'), config('session.secure'), false, false, config('session.same_site') ?? null )); } } return $response; } } |
app\Http\Kernel.phpに追加します。
1 2 3 4 5 6 7 8 9 10 |
'web' => [ \App\Http\Middleware\EncryptCookies::class, \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class, \Illuminate\Session\Middleware\StartSession::class, // \Illuminate\Session\Middleware\AuthenticateSession::class, \Illuminate\View\Middleware\ShareErrorsFromSession::class, \App\Http\Middleware\VerifyCsrfToken::class, \Illuminate\Routing\Middleware\SubstituteBindings::class, GenerateApiToken::class, // <- 追加 ], |
あと、Cookieの暗号化の対象から外します。
これ、やらないと動きませんでした。本当はトークンをハッシュ化したり
そもそもLaravel Passportとかそっちでがんばれ
という話かもしれませんが、今回は、ライトに、ライトに。
app\Http\Middleware\EncryptCookies.php の $exceptに追加します。
1 2 3 |
protected $except = [ 'api_token', ]; |
APIのルーティング
認証が必要なAPIには、auth:api
のミドルウェアが必要です。
私のバージョンのroutes/api.phpには
1 2 3 |
Route::middleware('auth:api')->get('/user', function (Request $request) { return $request->user(); }); |
すでにいらっしゃいました。auth:apiを持ったAPIが。
他にも、認証が必要なAPIは、ルーティング設定で記述するなり、
Controllerのコンストラクタに記述するなり、好きにしたらいいじゃない。
javascript
ここまでLaravelの設定でしたが、あとはJavascriptからajax通信をしましょう。
いうまでもなく、みんな大好きjQueryです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
$.ajax({ 'url': '', // <- ルーティング次第 'type': 'post', // <- ルーティング次第 'dataType': 'json', 'data': { // リクエストのBODY部 }, 'headers': { 'Authorization': 'Bearer ' + Cookies.get('api_token'), // <- これ }, }).done(function(response){ alert('success'); }).fail(function(response){ alert('error'); }); |
あ、Cookieの取得には、js-cookieを使ってます。
詳しくはコチラ ⇒ GitHub – js-cookie/js-cookie: A simple, lightweight JavaScript API for handling browser cookies
headersに、リクエストヘッダに’Authorization: Bearer [APIトークン]’が含まれるように
値を放り込んでいます。
ミドルウェアは、このヘッダのトークンを見て、確認をするようですね。
最後に
トークンの有効期限をサーバでもチェックしたり、
usersテーブルのapi_tokenをハッシュ化しておいたり、
ログアウトした時はさすがにapi_tokenをnullにしてみたり、
ユーザが任意にトークンの更新をできるようにしたり、
なにかもろもろ足りない感はありますが
ライトにいくなら、こんなものでしょうか。
Laravel Passportは時間があったら試します。
r.tanakaがお届けしました。
ごきげんよう