今回はLaravel API認証サービスのsanctumやpassportを使わないで認証を行ってみようと思います!
今回はmiddlewareも自作してオレオレ認証も作っていきます!
やりたいことはguardを使った通常ログインとuserテーブルにis_adminカラムを追加してフラグとして利用してtrue/falseの値で利用できるroutingを変えていこうと思います!
そのためにもmiddlewareも自作してみます。
Laravel8.xはすでにインストールされている前提で進めていきます。
Table of Contents
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');
}
}
Code language: HTML, XML (xml)
追加するのは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
];
Code language: PHP (php)
これでOKじゃあダミーデータの作成へ。
ダミーデータの作成
まず初めにログインするユーザのダミーデータを作成。
参考↓
https://yama-weblog.com/create-dummy-data-using-seeder-in-laravel8/
$ 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),
],
]);
}
}
Code language: HTML, XML (xml)
そしたら、DatabaseSeeder.phpに以下を追加しましょう。
{プロジェクト名}/database/seeders/DatabaseTableSeeder.php
public function run()
{
// \App\Models\User::factory(10)->create();
//seederの呼び出しを行う。
$this->call([
UserTableSeeder::class,
]);
}
Code language: PHP (php)
php migration refresh
php artisan db:seed
Code language: CSS (css)
これでOKなはず!ではGuardの設定をしていきます。
guardの設定とログイン
configの設定
まずはconfigの設定から。
guardを触るときは以下から操作します。
以下の記事はguardを利用する際には参考にさせていただきました。
{プロジェクト名}/config/auth.php
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
//以下が追加
'api' => [
'driver' => 'token', //usersテーブルのtoken_apiを参照
'provider' => 'users',
],
],
Code language: PHP (php)
そしたらログインの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!';
}
}
Code language: HTML, XML (xml)
ログインをするときにapi_tokenを再生成するようになっています!
ただ、このままだったらただのログイン機能で終わってしまうので、usersテーブルのカラムの値によって振り分けることができないので、そこの振り分けができるようにします。
そのためにmiddlewareを作成していきます~
middlewareの作成
参考ブログ
ほい、では作っていきます。
php artisan make:middleware AdminAuth
Code language: CSS (css)
{プロジェクト名}/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.');
}
}
Code language: HTML, XML (xml)
ほいー、middlewareができました。自作ですね。
ただ、このままだとmiddlewareは使えないので登録しますね。
{プロジェクト名}/app/Http/Kernel.phpのprotected $routeMiddlewareに以下を追加します。
'admin_auth' => \App\Http\Middleware\AdminAuth::class
Code language: PHP (php)
これで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!';
});
});
Code language: HTML, XML (xml)
ほい!こんな感じで書いてみました!
初めにログインして、取得した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とか使った方が簡単にはできるかと思います~
手順も少ないしね。