Laravel Token API認証(Authentication)を理解する
人は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(トークン)を利用して認証を行います。
driver, providerについて
web guardとapi guardに対しdriverやproviderを設定する必要があります。またwebやapiといった名前は変更ができない名前ではなく、任意の名前をつけること新たにguardを追加することも可能です。
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
'api' => [
'driver' => 'token',
'provider' => 'users',
'hash' => false,
],
],
driverはどのように認証を行うかを設定する項目でsessionとtokenがデフォルトでサポートされています。sessionではセッションやcookie、storageを利用して認証、tokenではランダムな英数字から構成された文字列を利用して認証を行います。
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');
});
}
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の列に値を挿入できるように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),
]);
}
設定が完了したら、ユーザ登録画面を使ってユーザの登録を行ってください。
ユーザの登録が完了したら、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();
});
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の基本的な使用方法を理解することができました。