イントロダクション
アプリケーションの各ユーザーに結びつけたランダムトークンを利用し、API認証を行うシンプルな手法をデフォルトとしてLaravelは採用しています。config/auth.php
設定ファイルの中で、api
ガードはtoken
ドライバを定義し、使用しています。このドライバーは、受信したリクエストのAPIトークンを調べ、データベース上のユーザーに結びつけたトークンと一致するか検証することに責任を持っています。
Note: Laravelでは、シンプルなトークンベースの認証ガードを提供していますが、API認証を提供する堅牢なプロダクションアプリケーションでは、Laravel Passportの使用を考慮することを強く推奨します。
設定
データベースの準備
token
ドライバを使用する前に、users
テーブルへapi_token
カラムを追加するマイグレーションを作成する必要があります。
Schema::table('users', function ($table) {
$table->string('api_token', 80)->after('password')
->unique()
->nullable()
->default(null);
});
マイグレーションできたら、migrate
Artisanコマンドを実行します。
Tip!! 他のカラム名を使う場合は、
config/auth.php
設定ファイル中のstorage_key
設定オプションを必ず更新してください。
トークン生成
users
テーブルへapi_token
カラムを追加したら、アプリケーションに登録している各ユーザーへ、ランダムなAPIトークンを割り付ける準備が整いました。ユーザーの登録でUser
モデル生成時に、トークンを割り付けるべきでしょう。laravel/ui
Composerパッケージが提供する認証スカフォールドを使用する場合は、RegisterController
のcreate
メソッドで行っています。
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Str;
/**
* 登録バリデーション後に、新ユーザーインスタンスの生成
*
* @param array $data
* @return \App\User
*/
protected function create(array $data)
{
return User::forceCreate([
'name' => $data['name'],
'email' => $data['email'],
'password' => Hash::make($data['password']),
'api_token' => Str::random(80),
]);
}
トークンのハッシュ
前記の例では、APIトークンはデータベースへ平文のまま保存されます。SHA-256を使用し、APIトークンをハッシュしたい場合は、api
ガードのhash
オプションをtrue
に設定してください。api
ガードはconfig/auth.php
設定ファイルで定義されています。
'api' => [
'driver' => 'token',
'provider' => 'users',
'hash' => true,
],
ハッシュ済みトークンの生成
ハッシュ済みAPIトークンを使用する場合、ユーザー登録時にAPIトークンを生成してはいけません。代わりに、アプリケーション中にAPIトークン管理ページを実装する必要があります。このページでユーザーにAPIトークンの初期化と再生成を提供します。あるユーザーがトークンの初期化や再生成をリクエストしたら、トークンのハッシュ済みコピーをデータベースへ保存し、ビューやフロントエンドクライアントで一度だけ表示するために、平文のコピーを返す必要があります。
たとえば、指定したユーザーのトークンを初期化/再生成し、JSONレスポンスとして平文トークンを返すコントローラメソッドは、次のようになるでしょう。
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Support\Str;
class ApiTokenController extends Controller
{
/**
* 認証済みのユーザーのAPIトークンを更新する
*
* @param \Illuminate\Http\Request $request
* @return array
*/
public function update(Request $request)
{
$token = Str::random(80);
$request->user()->forceFill([
'api_token' => hash('sha256', $token),
])->save();
return ['token' => $token];
}
}
Tip!! 上記例のAPIトークンは、十分なエントロピーを持ちますので、「レインボーテーブル」を作成してハッシュ済みトークンのオリジナル値を探し出すのは、非現実的になります。そのため、
bcrypt
などの遅いハッシュ方法は必要ありません。
ルートの保護
Laravelは、受信したリクエストのAPIトークンを自動的にバリデートする、認証ガードを提供しています。アクセストークンの有効性が必要なルートへ、auth:api
ミドルウェアを指定するだけです。
use Illuminate\Http\Request;
Route::middleware('auth:api')->get('/user', function (Request $request) {
return $request->user();
});
リクエストへのトークン付加
アプリケーションへAPIトークンを渡す方法はいくつかあります。Guzzle HTTPライブラリを使用したときの利用方法をデモンストレーションするために、いくつかのアプローチを検討してみます。アプリケーションの必要に合わせて選択してください。
クエリ文字列
アプリケーションのAPI利用側が、api_token
クエリ文字列の値としてトークンを指定できます。
$response = $client->request('GET', '/api/user?api_token='.$token);
ペイロードのリクエスト
アプリケーションのAPI利用側が、リクエストフォームのapi_token
パラメータへ、APIトークンを含められます。
$response = $client->request('POST', '/api/user', [
'headers' => [
'Accept' => 'application/json',
],
'form_params' => [
'api_token' => $token,
],
]);
Bearerトークン
アプリケーションのAPI利用側が、リクエストのAuthorization
ヘッダへBearer
トークンとして、APIトークンを提供できます。
$response = $client->request('POST', '/api/user', [
'headers' => [
'Authorization' => 'Bearer '.$token,
'Accept' => 'application/json',
],
]);