【Laravel8.x】guardと自作middlewareを使って認証APIを作ってみた。単一テーブルマルチ認証?

Laravel

今回はLaravel API認証サービスのsanctumやpassportを使わないで認証を行ってみようと思います!

今回はmiddlewareも自作してオレオレ認証も作っていきます!

やりたいことはguardを使った通常ログインとuserテーブルにis_adminカラムを追加してフラグとして利用してtrue/falseの値で利用できるroutingを変えていこうと思います!

そのためにもmiddlewareも自作してみます。

Laravel8.xはすでにインストールされている前提で進めていきます。

Modelとusersテーブルの修正

usersテーブルの修正

seederでダミーデータを作る前に、usersテーブルの修正をしておきます。

{プロジェクト名}/database/migrations/yyyy_mm_dd_xxxxxx_create_users_table.php

<?php

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

class CreateUsersTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    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が参照するapi_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');
    }
}

追加するのはis_adminとapi_tokenカラムです。

Modelの修正

次にモデル。

{プロジェクト名}/app/Models/User.php

//$fillable内にapi_tokenとis_adminを追加
    protected $fillable = [
        'name',
        'email',
        'password',
        'api_token', //add
        'is_admin', //add
    ];

これでOKじゃあダミーデータの作成へ。

ダミーデータの作成

まず初めにログインするユーザのダミーデータを作成。

参考↓

【ダミーデータの作成】laravel8系でseederを使ってダミーデータを作成してみた。
今回はseederを使ってダミーデータを作成してみます。使うのはlaravel8系です。シーダーの作成#シーダ名はアッパーキャメル型で書く。 ex.TestTableSeederphp artisan make:seeder シーダ...
$ php artisan make:seeder  UserTableSeeder

UserTableSeederの修正
{プロジェクト名}/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
{
    /**
     * Run the database seeds.
     *
     * @return void
     */
    public function run()
    {
        //userのダミーデータを2つ作成
        DB::table('users')->insert([
            [
                //admin権限を持つユーザー
                'name' => 'test1',
                'email' => 'test1@test',
                'is_admin' => true,
                'password' => bcrypt('test'),
                'api_token' => Str::random(60),
            ],
            [
                //admin権限を持たないユーザー
                'name' => 'test2',
                'email' => 'test2@test',
                'is_admin' => false,
                'password' => bcrypt('test'),
                'api_token' => Str::random(60),
            ],
        ]);
    }
}

そしたら、DatabaseSeeder.phpに以下を追加しましょう。

{プロジェクト名}/database/seeders/DatabaseTableSeeder.php

public function run()
{
    // \App\Models\User::factory(10)->create();
    //seederの呼び出しを行う。
    $this->call([
        UserTableSeeder::class,
    ]);
}
php migration refresh
php artisan db:seed

これでOKなはず!ではGuardの設定をしていきます。

guardの設定とログイン

configの設定

まずはconfigの設定から。

guardを触るときは以下から操作します。

以下の記事はguardを利用する際には参考にさせていただきました。

[図解] Laravel の認証周りのややこしいあれこれ。

{プロジェクト名}/config/auth.php

    'guards' => [
        'web' => [
            'driver' => 'session',
            'provider' => 'users',
        ],
        //以下が追加
        'api' => [
            'driver' => 'token', //usersテーブルのtoken_apiを参照
            'provider' => 'users',
        ],
    ],

そしたらログインのAPIを作っていきます。

Login API作成

参考

https://reffect.co.jp/laravel/laravel-api-authentication-token-base#users
php artisan make:controller Auth/LoginController

{プロジェクト名}/app/Http/Controllers/Auth/LoginController.php

<?php

namespace App\Http\Controllers\Auth;

use App\Http\Controllers\Controller;
use Illuminate\Http\Request;

//add
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) {

        $credentials = $request->only(['email', 'password']); //requestからemail,passwordだけ取ってくる。
        $guard = $request->guard;

        //attempt()でユーザを認証する。
        if(Auth::guard($guard)->attempt($credentials)) {

            //ログインをする度にapi_tokenのアップデート
            $user_info = User::whereEmail($request->email)->first(); //userのメールアドレスの取得
            $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!';
    }
}

ログインをするときにapi_tokenを再生成するようになっています!

ただ、このままだったらただのログイン機能で終わってしまうので、usersテーブルのカラムの値によって振り分けることができないので、そこの振り分けができるようにします。

そのためにmiddlewareを作成していきます~

middlewareの作成

参考ブログ

https://blog.capilano-fw.com/?p=3987

ほい、では作っていきます。

php artisan make:middleware AdminAuth

{プロジェクト名}/app/Http/Middleware/AdminAuth.phpの修正。

<?php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;

class AdminAuth
{
    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return mixed
     */

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

            return $next($request);
        }

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

ほいー、middlewareができました。自作ですね。

ただ、このままだとmiddlewareは使えないので登録しますね。

{プロジェクト名}/app/Http/Kernel.phpのprotected $routeMiddlewareに以下を追加します。

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

これでmiddlewareも使えるようになりました!

よし、これで最後に答え合わせです。

routing設定

ではrouteを書いていきます!
{プロジェクト名}/route/api.php

<?php

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;

//追加
use App\Http\Controllers\Auth\LoginController;

/*
|--------------------------------------------------------------------------
| API Routes
|--------------------------------------------------------------------------
|
| Here is where you can register API routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| is assigned the "api" middleware group. Enjoy building your API!
|
*/

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

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権限、admin権限のあるユーザの操作
Route::middleware('auth:api')->group(function(){
    Route::get('/user', function(){
        return 'you are member user!';
    });
});

ほい!こんな感じで書いてみました!

初めにログインして、取得したtokenを持って、adminかuserにアクセスしてみましょう!

localhost/api/login  (passwordとemailをPOSTで投げてtokenを取得)
localhost/api/admin  (is_admin=trueのユーザのtokenを持ってGETでアクセスする falseのuserはアクセスできない)
localhost/api/user  (loginできたuserのtokenを持っていると誰でもGETでアクセスが可能)

POSTMANで試すといいと思います!

まとめ

やり方さえわかったらすぐにできる。

ただ、sanctumとか使った方が簡単にはできるかと思います~

手順も少ないしね。

コメント

タイトルとURLをコピーしました