Token APIはLaravel6.xではこの機能と同じものが提供されているため本書通りに設定が可能ですが、Laravel7.XからはLaravel Airlockを利用します。Laravel8.XからはLaravel AirlockからLaravel Sanctumに名称が変わっています。これからLaravelを始める
人はLaravel9になるのでLaravel Sanctumを確認してください。

LaravelではデフォルトでトークンベースのシンプルなAPI認証の機能が備わっていますが、公式マニュアルではLaravel Passportを使用することを強く推奨していることを理解の上読み進めてください。

While Laravel ships with a simple, token based authentication guard, we strongly recommend you consider using Laravel Passport(Laravelにはシンプルなトークンベースの認証ガードが提供されていますが、Laravel Passportを利用することを強く推奨します)

Laravel Token APIはユーザの登録時にランダムな英数字で作られたトークンが各ユーザに割り当てられ、割り当てられたトークンを利用して認証に利用するといったシンプルな機能です。

本文書では、Laravel Passportを使ったAPIではなくデフォルトのTokenベースのシンプルなAPIを利用してLaravelでのAPIの設定方法を確認します。また、Laravelの認証機能を理解する上で重要なGuardについても説明を行っています。

APIの設定についてはできるだけ公式マニュアルに沿って行っています。動作確認にはLaravelのバージョン5.8を利用しています。

ログインの認証については下記を参考にしてください。

Authenticationの設定内容について

カスタマイズを行いたい時以外は設定変更を行うことはありませんが、認証に関する設定はconfig/auth.phpファイルで行うことができます。

Guardとは

Laravelの認証ではGuardという単語が頻繁に出てきます。単語だけ見ると何かを守る(ガードする)ためのものに関連するのではないかと容易に予想ができます。Guardは外部からのアクセスの認証に関する機能でGuardによってLaravelのアプリケーションにアクセスしてくるユーザをどのような方法で識別するのかということを定義します。

例えばconfig/auth.phpの中には、デフォルトでweb guardとapi guardという2つのGuardが設定されています。web guardはSessionを利用してユーザに関する情報を保持することで認証を行います。api guardはToken(トークン)を利用して認証を行います。

web guardはphp artisan make:authによって追加されるメールアドレスとパスワードを使用したユーザのログイン認証に利用するGuardです。

driver, providerについて

web guardとapi guardに対しdriverやproviderを設定する必要があります。またwebやapiといった名前は変更ができない名前ではなく、任意の名前をつけること新たにguardを追加することも可能です。


'guards' => [
    'web' => [
        'driver' => 'session',
        'provider' => 'users',
    ],

    'api' => [
        'driver' => 'token',
        'provider' => 'users',
        'hash' => false,
    ],
],
multi authentication機能を実装したい場合は新たにGuardを追加して行います。

driverはどのように認証を行うかを設定する項目でsessionとtokenがデフォルトでサポートされています。sessionではセッションやcookie、storageを利用して認証、tokenではランダムな英数字から構成された文字列を利用して認証を行います。

冒頭で出てきたLaravel Passportを利用する場合は、apiのdriverはtokenではなくpassportになります。このようにデフォルトでサポートされているもの以外のdriverも設定可能です。

providerはどこから認証に必要な情報を取得するかを設定する項目でどちらもusersが設定されています。

hashはtokenを暗号化するかどうかの設定です。今回は暗号化を使わないのでデフォルトのままfalseを設定しておきます。

web, apiで指定されているproviderのusersは下記のようにprividersの中で定義されておりdriverとmodelの2つの設定項目を持っています。


'providers' => [
    'users' => [
        'driver' => 'eloquent',
        'model' => App\User::class,
    ],

driverにはdatabaseとeloquentがサポートされています。databaseは直接データベースから情報を取得する場合に指定しeloquentはモデルを経由して取得する場合に指定します。

web, apiはどちらもApp¥Userモデルを経由してusersテーブルから認証に必要な情報を取得しますが、apiの場合はusersテーブルに新たにtokenの列を追加する必要があります。

Guardのdriverをtokenにした場合はすべてのリクエストに対してtokenを確認しテーブルに保存されているtokenとその値が一致するのかチェックを行います。

APIを使用するための環境設定

APIを使用するためにはデータベースやusersテーブルが必要です。事前にphp artisan migrateコマンドを使用してusersテーブルが作成できる環境構築まで行ってください。

APIの設定

usersテーブルへの列の追加

php artisan migrate実行後に作成されるusersテーブルに新たにtoken_api列を追加するためにmigrationファイルの作成を行います。


$ php artisan make:migration add_api_token_to_users_table --table=users
Created Migration: 2019_07_27_115730_add_api_token_to_users_table

database¥migrationsフォルダに作成されたmigrationファイルにapi_token列を追加します。


public function up()
{
    Schema::table('users', function (Blueprint $table) {
        $table->string('api_token', 80)->after('password')
                ->unique()
                ->nullable()
                ->default(null);
    });
}

追加するapi_token列はpassword列の後に追加されるようにafterを指定しています。さらにユニークでデフォルト値はnull、null値を入力することも可能なnullableも設定しています。

修正が必要な時のため、downメソッドも追加しておきます。


public function down()
{
    Schema::table('users', function (Blueprint $table) {
        $table->dropColumn('api_token');
    });
}
php artisan migrate:rollbackやrefreshを使ってClass ‘Doctrine\DBAL\Driver\PDOSqlite\Driver’ not foundエラーが発生した場合は、composerを使ってdoctrine/dbalパッケージをインストールする必要があります。インストールを実行するコマンドは、composer require doctrine/dbalです。

migrationファイルの更新作業が完了したら、php artisan migrateコマンドを実行して列の追加を行ってください。


 $ php artisan migrate
Migrating: 2019_07_27_115730_add_api_token_to_users_table
Migrated:  2019_07_27_115730_add_api_token_to_users_table (0.01 seconds)
列名をapi_token以外に設定する場合は、auth.phpファイルでstorage_keyオプションを設定する必要があるようですが、変更についての動作確認を行っていません。

api_tokenの列に値を挿入できるようにApp¥User.phpの$fillableにapi_tokenを追加します。


protected $fillable = [
    'name', 'email', 'password','api_token'
];

api_token列への値の挿入

api_tokenのデフォルト値はnullに設定されるためユーザ作成後にユーザ毎に個別に設定することが可能です。今回は、ユーザ登録時に実行されるcreateメソッドを変更することでapi_tokenを追加します。

App¥Http¥Controller¥Auth¥RegisterController.phpファイルを開いてcreateファイルを下記のように変更します。


protected function create(array $data)
{
    return User::create([
        'name' => $data['name'],
        'email' => $data['email'],
        'password' => Hash::make($data['password']),
        'api_token' => str_random(60),
    ]);
}

設定が完了したら、ユーザ登録画面を使ってユーザの登録を行ってください。

Register画面はphp artisan make:authを実行していない場合は表示されません。
ユーザ登録画面
ユーザ登録画面

ユーザの登録が完了したら、tinkerを使ってapi_token列に値が入っているか確認を行います。下記のようにapi_tokenにはランダムは英数字の文字列が入っています。


$ php artisan tinker
Psy Shell v0.9.9 (PHP 7.1.23 — cli) by Justin Hileman
>>> $user = App\User::find(1)
=> App\User {#2973
     id: "1",
     name: "John Doe",
     email: "johndoe@example.com",
     email_verified_at: null,
     created_at: "2019-07-27 12:26:30",
     updated_at: "2019-07-27 12:26:30",
     api_token: "eQ5sIys2fhPDFCVFcJSH7El24gxk6SRn4wUAQO5or4KDS7UELipLraG4bRD4",
   }
>>>

api認証ではapi_tokenに入っている値を利用します。

Tokenを使ったアクセス

ルーティングファイルのweb.phpとは別にAPI用のルーティングファイルapi.phpがデフォルトで準備されています。api.phpの中身を下記のようになっています。


Route::middleware('auth:api')->get('/user', function (Request $request) {
    return $request->user();
});
api認証を使用したい場合はmiddlewareでは必ずauth:apiと設定しなければなりません。authのみだとデフォルトのwebが認証に使用されるためです。Guardのデフォルト値はconfig/auth.phpファイルに記述されています。

middlewareを使ってAPIの認証によるアクセス制限を行っています。api.phpに記述された/userへのアクセスは、/userではなくその前に/apiをつけて/api/userとします。

開発サーバを使っている場合は、URLがhttp://127.0.0.1:8000になるのでhttp://127.0.0.1:8000/api/userでアクセスを行います。

curlコマンドを使用してアクセスを行ってみます。


$ curl http://127.0.0.1:8000/api/user

api_tokenの情報がつけられていないのでアクセスに失敗し、loginページへのリダイレクトのHTMLが表示されます。


$ curl http://127.0.0.1:8000/api/user
<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8" />
        <meta http-equiv="refresh" content="0;url=http://127.0.0.1:8000/login" />

        <title>Redirecting to http://127.0.0.1:8000/login</title>
    </head>
    <body>
        Redirecting to <a href="http://127.0.0.1:8000/login">http://127.0.0.1:8000/login</a>.
    </body>

今度は、api_tokenをつけてアクセスを行います。今回は認証に成功して、JSONでユーザ情報が戻されていることを確認することができます。


$ curl http://127.0.0.1:8000/api/user?api_token=eQ5sIys2fhPDFCVFcJSH7El24gxk6SRn4wUAQO5or4KDS7UELipLraG4bRD4
{"id":1,"name":"John Doe","email":"johndoe@example.com","email_verified_at":null,"created_at":"2019-07-27 12:26:30","updated_at":"2019-07-27 12:26:30","api_token":"eQ5sIys2fhPDFCVFcJSH7El24gxk6SRn4wUAQO5or4KDS7UELipLraG4bRD4"}

次にmiddlewareをなくした状態でアクセスを行います。api.phpを開いて下記のように書き換えます。


Route::get('/user', function (Request $request) {
    return $request->user();
});

middlewareをなくしたので、api_tokenをつけなくてもユーザ情報が取得できると考えた人も多いかと思いますが、実際は何も表示されません。


$ curl http://127.0.0.1:8000/api/user

api.phpのreturnで$request->user()となっていますが、api_tokenがないためユーザ情報を取得することができないために$request->user()には何も表示されません。これをreturn ‘test’;のように文字列にすると下記のようにtestが表示されます。


 $ curl http://127.0.0.1:8000/api/user
test

curl以外のアクセス方法

今回は簡単なcurlコマンドを使ってアクセスを行いましたが、JavaScriptを利用して/api/userにアクセスして情報を取得したい場合はあります。axiosを利用している場合は下記のように行うことができます。


axios.get('/api/user?api_token=eQ5sIys2fhPDFCVFcJSH7El24gxk6SRn4wUAQO5or4KDS7UELipLraG4bRD4')
  .then(function (response) {
    // handle success
    console.log(response);
  })

ここまでの動作確認でLaravel API TOKENの基本的な使用方法を理解することができました。