DIVX テックブログ

catch-img

APIを理解するためにLaravelで認証APIを作ってみた


目次[非表示]

  1. 1.WebAPIとは
    1. 1.1.API
  2. 2.HTTPリクエストとは
    1. 2.1.リクエストライン
    2. 2.2.リクエストヘッダー
    3. 2.3.メッセージボディ
  3. 3.HTTPメソッド
    1. 3.1.GETメソッド
    2. 3.2.URL
    3. 3.3.POSTメソッド
  4. 4.HTTPプロトコルとは
    1. 4.1.プロトコル
  5. 5.APIのメリットとデメリット
    1. 5.1.メリット
      1. 5.1.1.システム開発が効率化できる
      2. 5.1.2.最新情報の取得が簡単
    2. 5.2.デメリット
    3. 5.3.API提供元に依存してしまう
    4. 5.4.サーバー障害などに対応できない
  6. 6.Laravelで認証APIを作成
    1. 6.1.実行環境
    2. 6.2.Laravelプロジェクトの作成
    3. 6.3.Laravelファイルの修正
    4. 6.4.ダミーデータの作成
    5. 6.5.データベースの準備
    6. 6.6.configの設定
      1. 6.6.1.LoginControllerの作成
    7. 6.7.Middlewareの作成
    8. 6.8.ルーティングの設定
    9. 6.9.POSTMANで確認
  7. 7.終わりに
  8. 8.参考記事

こんにちは。株式会社divxのエンジニア大久保です。 本記事ではAPIを理解するためにLaravelで認証APIを作ってみたいと思います。

いきなりですが、こんな会話聞いたことありませんか?

「は〜んそこでAPI叩いてるんだ」、「そこでAPIを叩けばいいんですね」

え?どういうこと(笑)はじめて聞いた時には頭の中はクエスチョンマークでいっぱいになっていました。

APIキーとパラメーターを持って提供先の認証のドアを叩きに行くイメージなのでしょうか?それとも、叩くはhitなので、hit APIとでも言うから? 話が脱線してしまったので、話を戻します。

APIの仕組みを理解していないのにAPIを叩くとか、したり顔で言ってしまうのを避けたいなと考えています。 言葉の実態を捉えられていないのに、みんな言っているから使ってしまうことはよくあることです。

この記事を最後まで見ていただければ今日から「APIを叩く」という言葉を後ろめたさを持たずに使うことができるようになってます。 まずはLaravelで認証APIの作成の前に、APIの前提知識をつけていきたいと思います。

WebAPIとは

HTTPプロトコルを利用してネットワーク越しに呼び出すAPIのことです。

Web上でユニークなURIに対して、HTTPリクエストを投げて、レスポンスとして情報を取得するのが、WebAPIの基本的な処理の流れになります。

WebAPIでは通信プロトコルとしてHTTPを標準で使用します。

API

ApplicationProgramInterface(アプリケーションプログラムインターフェイス)の略で、あるソフトウェアから他のソフトウェアを制御するインターフェイスを意味します。

ソフトウェアの内部構造を知らなくても、APIを介してソフトウェアに接続して制御できます。

HTTPリクエストとは

Webサーバーへ送信するGET(ゲット)やPOST(ポスト)などによるデータ送信のリクエストのことです。

HTTPリクエストは、リクエストライン、リクエストヘッダー、メッセージボディの3つで構成されています。

リクエストライン

HTTPリクエストを構成する3つの部品のひとつで、メソッド、リクエスト先URL、HTTPのバージョンなどが含まれます。

リクエストヘッダー

クッキーやキープアライブなどHTTP通信に関わる重要な制御情報やメタデータが格納されています。また、クラウド固有の拡張ヘッダーなどもあります。

メッセージボディ

送信する実際のデータ領域のことです。補足のメモ書きスペースみたいなもので、POST通信の場合は、受け渡されるパラメーターの内容が記述されます。

GET通信のように補足の必要がない場合は、とくに何も書かれません。

HTTPメソッド

クライアントがサーバーに対してHTTPリクエストを送信したときに、サーバーにしてほしい操作を伝えるために使用します。

システムに必要な4つの主要機能である機能をまとめた表現で、CRUD(クラッド)という用語があります。

CRUDはCreate(生成)Read(読み取り)Update(更新) Delete(削除)の頭文字を並べた用語で、よく使用されるHTTPメソッドです。

おおよそのHTTPリクエストはPOSTとGETの2つのメソッドで実装されているケースが多いです。

GETメソッド

HTTP通信でサーバーにリソースをリクエストする方法の1つで、追加情報がURLパラメーターとして付与される通信方式です。

リクエストの結果、サーバ側のリソースに変化を起こす事は基本的にはありません。

たとえばサイト上の「検索」ボタンを押しても、ブラウザにURLを直接入力しても、アプリケーションの状態は変わりません。

URL

Uniform Resource Locator(ユニフォーム・リソース・ロケーター)の略で、インターネット上に存在するあらゆるリソースの場所を示すものです。

例:https://www.divx.co.jp/example/wp/index.html

いわゆるWeb上の住所のことです。

POSTメソッド

GETメソッドとは異なり、リクエストするリソースへの追加情報をURLではなくメッセージボディに含める通信方式です。
リクエスト後は、サーバ側のリソースに何らかの変化を起こしている可能性があります。
たとえばユーザー登録ボタンを押すと、ユーザー作成によってアプリケーションの状態に変化を起こします。

HTTPプロトコルとは

HyperTextTransferProtocol(ハイパーテキスト・トランスファー・プロトコル)の略のことで、WebサーバーとクライアントのWebブラウザがデータを送受信するために使われるプロトコルです。

プロトコル

ネットワークで通信するときに、コンピューターやネットワーク機器が守らなければならない仕組み、約束事のことです。

APIのメリットとデメリット

APIを使用することによる、メリットとデメリットを考えてみました。

メリット

  • システム開発が効率化できる
  • 最新の情報の取得が簡単

デメリット

  • API提供元に依存してしまう
  • サーバー障害などに対応できない

メリット

システム開発が効率化できる

API連携によってシステムが使える場合、システムやサービスを1から開発する必要がないため、リソースを大きく削減することが可能です。

最新情報の取得が簡単

APIを通して、各サービスの最新情報を自動的に取得し、利用することも可能です。

たとえば、自社サイトでAPI提供者の商品を販売している場合、販売価格や商品仕様の変更も自動で反映されるため、情報の確認や更新の手間が省けます。

デメリット

API提供元に依存してしまう

API提供元が仕様変更をした場合、API利用者もそれに合わせて仕様変更が必要となる場合はあります。

また、API提供元のサービスが停止した場合は、そもそも連携自体ができなくなってしまう場合があります。

サーバー障害などに対応できない

API提供元のサーバーにトラブルが起きた場合、自社のサービスにも影響を受けてしまいます。

このトラブルに対しては自社で対応できないという問題点もあるため、あらゆるトラブルを想定しておくことが大切です。

Laravelで認証APIを作成

それでは実際にLaravelで認証APIを作っていきたいと思います。
今回の実行環境は以下の通りになっております。

実行環境

MacBook Air(M1,2020)
Mac OS Montereyバージョン11.6.4

$ php -v
PHP 8.1.9 (cli) (built: Aug 4 2022 15:11:08) (NTS)

$ composer -v
Composer version 2.3.9 2022-07-05 16:52:11

$ php artisan -V
Laravel Framework 9.26.1

$ brew --version
Homebrew 3.5.10

$ mysql --version
mysql Ver 14.14 Distrib 5.6.51, for osx10.17 (x86_64) using EditLine wrapper

また、今回は下記がインストールされていることを前提に進めていきます。

Laravelプロジェクトの作成

それでは早速Laravelプロジェクトの作成をします。

$ composer create-project laravel/laravel tech_blog

プロジェクト作成後、Artisan serveコマンドを使用して、Laravelのローカル開発サーバーを起動します。

$ php artisan serve

INFO Server running on[<http://127.0.0.1:8000>].

Press Ctrl+C to stop the server

Laravelのローカル開発サーバーを起動すると、Webブラウザでhttp://localhost:8000から下記アプリケーションへアクセスできるようになります。

Laravelプロジェクトの作成

Laravelファイルの修正

元々Laravelで用意されているUser Modelを修正します。

指定したカラムに対して割り当ての許可設定をしました。

app/Models/User.php

//追加
protected $fillable =[
'name',
'email',
'password',
'api_token',
'is_admin',
];

次はusers_tableを修正します。

追加するのは先ほどホワイトリスト方式で許可した、is_adminとapi_tokenカラムです。

database/migrations/2014_10_12_000000_create_users_table.php

<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class CreateUsersTable extends Migration
public function up()
{
Schema::create('users', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->string('email')->unique();
$table->timestamp('email_verified_at')->nullable();
$table->string('password');
$table->string('api_token', 80)->unique()->nullable()->default(null)->comment('guardが参照するtoken');
$table->boolean('is_admin')->default(false)->comment('true->admin権限をあり');
$table->rememberToken();
$table->timestamps();
});
}

/**
 * Reverse the migrations.
 *
 * @return void
 */
public function down()
{
    Schema::dropIfExists('users');
}

ダミーデータの作成

ログインするユーザーのダミーデータをSeederで作成します。

Seederは、データベースに初期データを登録するために使用します。

$ php artisan make:seeder UserTableSeeder

php artisanコマンドで生成したUserTableSeederの修正をします。admin権限を持つユーザーとadmin権限を持たないユーザーの、ダミーデータを2つ作成します。

database/seeders/UserTableSeeder.php

<?php

namespace Database\Seeders;

use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;

class UserTableSeeder extends Seeder
    public function run()
    {
        //ユーザーのダミーデータを2つ作成
        DB::table('users')->insert([
            [
                //admin権限を持つユーザー
                'name'      => 'test1',
                'email'     => 'test1@test',
                'is_admin'  => true,
                'password'  => bcrypt('test'),
                'api_token' => Str::random(60),
            ],
            [
                //admin権限を持たないユーザー
                'name'     => 'test',
                'email'    => 'test@test',
                'password' => bcrypt('test'),
                'token'    => Str::random(60),
            ],
        ]);
    }

Seederファイルの呼び出しを行うように修正します。

database/seeders/DatabaseSeeder.php

public function run()
{
    $this->call([
        UserTableSeeder::class,
    ]);
}

データベースの準備

次にSeederのユーザーデータを保存するデータベースを準備します。今回はmysqlを使っていきます。

$ mysql -u root
$ create database laravel;
// Query OK, 1 row affected (0.00 sec)

DBが登録できたかの確認コマンド

$ show databases;

ちゃんとデータベースが作成されていますね。

+--------------------------+
| Database |
+--------------------------+
| information_schema |
| laravel |
+--------------------------+

最後にphp artisan migrate;とphp artisan db:seed;コマンドを実行します。

mysql> exit
Bye
$ php artisan migrate;
$ php artisan db:seed;

configの設定

次はconfigの設定を変更します。受信したリクエストのtokenを調べて、データベース上のユーザーに結びつけたtokenと一致するか検証してくれます

config/auth.php

'guards' => [
        'web' => [
                'driver' => 'session',
                'provider' => 'users',
        ],
                //以下を追加
        'api' => [
                'driver' => 'token',
                'provider' => 'users',
        ],
],

LoginControllerの作成

$ php artisan make:controller Auth/LoginController

LoginControllerは認証処理を行う役割を持っています。

app/Http/Controllers/Auth/LoginController.php

<?php

namespace App\Http\Controllers\Auth;

use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use App\Models\User;
use \Symfony\Component\HttpFoundation\Response;
use Illuminate\Support\Str;

class LoginController extends Controller
{

    public function login(Request $request) {
            //requestからemail,passwordだけ取得する。
        $credentials = $request->only(['email', 'password']);
        $guard = $request->guard;

        if(Auth::guard($guard)->attempt($credentials)) {

            //api_tokenのアップデート
            $user_info = User::whereEmail($request->email)->first();
            $user_id = $user_info->id;

            //usersテーブルから対象userを見つけてapi_tokenを再生成する。
            $user = User::find($user_id);
            $user->api_token = Str::random(60);
            $user->save();

            //loginが成功するとtokenと共に情報をjson形式で返却。
            return response()->json([
                'token' => $user->api_token,
                'id'.   => $user->id,
                'name'  => $user->name,
                'email' => $user->email,
            ], Response::HTTP_OK);
        }

        return 'login failed!';
    }
}

Middlewareの作成

$ php artisan make:middleware AdminAuth

Middlewareを使ってユーザーが認証されていることを確認させます。

また、ユーザーが認証されていない場合、ユーザーをアプリケーションのログイン画面にリダイレクトしたりエラーメッセージを表示します。

app/Http/Middleware/AdminAuth.phpの修正。

<?php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;

class AdminAuth
//usersテーブルのis_adminを見て管理者権限があるかどうかを調べる。
public function handle(Request $request, Closure $next)
{
//auth()->check() 認証済かどうか
//auth()->user()->is_admin adminかどうか
if(auth()->check() && auth()->user()->is_admin)
{

        return $next($request);
    }

    //エラーメッセージ
    abort(403, 'This action is unauthorized.');
}

先ほど作ったMiddlewareを登録します。

app/Http/Kernel.php

'admin_auth' => \App\Http\Middleware\AdminAuth::class

ルーティングの設定

最後にルーティングの設定をします。これでLaravelの認証APIの作成は完了です。
route/api.php

<?php

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\Auth\LoginController;

Route::post('login', [LoginController::class, 'login']);

// admin権限の操作
Route::middleware('auth:api', 'admin_auth')->group(function(){
    Route::get('/admin', function(){
        return 'you are admin user!';
    });
});

// user権限の操作
Route::middleware('auth:api')->group(function(){
    Route::get('/user', function(){
        return 'you are member user!';
    });
});

POSTMANで確認

ここで本当にAPIが作れているか、POSTMANを使ってリクエストを送ってみたいと思います。

http://localhost:8000/api/loginに、admin権限のないuserのemailとpasswordをメッセージボディに含めてPOSTリクエストを送信してみると、認証トークンがtokenとして返却されました。

POSTMANで確認

取得したtokenをURLパラメーターに含めて、http://localhost:8000/localhost/api/admin にGETリクエストを送ります。

しかしid:2のuserはadmin権限がないので403エラーが返却さます。

POSTMANで確認


一方、http://localhost:8000/localhost/api/userへGETリクエストを送ると取得したい情報が返ってくることがわかります。 Laravelで認証APIの作成がしっかりとできていることが確認できました。

POSTMANで確認

終わりに

本記事では、APIを理解するためにLaravelでAPIを作成しました。 今まではなんとなくAPIっていう言葉を使っていましたが、実際にAPIを作成してリクエストを送ってみることで、理解が深まりました。

簡単なのでぜひLaravelで同じようなAPIを作成してみてはいかがでしょうか。

最後までお読み頂きまして、ありがとうございました。 APIを理解するための一助となる記事となれば嬉しいです。

divxでは一緒に働ける仲間を募集しています。
興味があるかたはぜひ採用ページを御覧ください。

  採用情報 | 株式会社divx(ディブエックス) 可能性を広げる転職を。DIVXの採用情報ページです。 株式会社divx(ディブエックス)


参考記事

WebAPI: The goodParts(書籍)
絵で見てわかるクラウドインフラとAPIの仕組み(書籍)
Laravel公式ドキュメント

お気軽にご相談ください


ご不明な点はお気軽に
お問い合わせください

サービス資料や
お役立ち資料はこちら

DIVXブログ

テックブログ タグ一覧

人気記事ランキング

GoTopイメージ