Otentikasi Pengguna Penuh dan Kontrol Akses – Tutorial Paspor Laravel, Pt. 1
Diterbitkan: 2022-03-11Saat mengembangkan aplikasi web, biasanya merupakan ide yang baik untuk membaginya menjadi dua tingkatan. API tingkat menengah berinteraksi dengan database, dan tingkat web biasanya terdiri dari SPA atau MPA front-end. Dengan cara ini, aplikasi web digabungkan secara lebih longgar, membuatnya lebih mudah untuk dikelola dan di-debug dalam jangka panjang.
Saat API telah dibuat, menyiapkan autentikasi dan status dalam konteks API stateless mungkin tampak agak bermasalah.
Pada artikel ini, kita akan melihat bagaimana menerapkan otentikasi pengguna penuh dan bentuk sederhana dari kontrol akses dalam API menggunakan Laravel dan Passport. Anda harus memiliki pengalaman bekerja dengan Laravel karena ini bukan tutorial pengantar.
Prasyarat instalasi:
- PHP 7+, MySQL, dan Apache (pengembang yang ingin menginstal ketiganya sekaligus dapat menggunakan XAMPP.)
- Komposer
- Laravel 7
- Paspor Laravel. Karena API umumnya tidak memiliki kewarganegaraan dan tidak menggunakan sesi, kami biasanya menggunakan token untuk menjaga status di antara permintaan. Laravel menggunakan library Passport untuk mengimplementasikan server OAuth2 lengkap yang dapat kita gunakan untuk otentikasi di API kita.
- Tukang pos, cURL, atau Insomnia untuk menguji API—ini terserah preferensi pribadi
- Editor teks pilihan Anda
- Pembantu Laravel (untuk Laravel 6.0 dan lebih tinggi)—setelah menginstal Laravel dan Passport, jalankan saja:
composer require laravel/helpers
Dengan menginstal di atas, kami siap untuk memulai. Pastikan untuk mengatur koneksi database Anda dengan mengedit file .env
.
Tutorial Paspor Laravel, Langkah 1: Tambahkan Pengontrol dan Model untuk Permintaan Dummy
Pertama, kita akan membuat pengontrol dan model untuk permintaan dummy. Model tidak akan banyak berguna dalam tutorial ini, hanya untuk memberikan gambaran tentang data yang dimaksudkan untuk dimanipulasi oleh pengontrol.
Sebelum membuat model dan controller, kita perlu membuat migrasi. Di jendela terminal—atau cmd.exe
, jika Anda menggunakan Windows—jalankan:
php artisan make:migration create_articles_table --create=articles
Sekarang, masuk ke folder database/migrations
dan buka file dengan nama yang mirip dengan xxxx_xx_xx_xxxxxx_create_articles_table.php
.
Dalam fungsi up
kelas, kita akan menulis ini:
Schema::create('articles', function (Blueprint $table) { $table->increments('id'); $table->string('title'); $table->string('body'); $table->integer('user_id'); $table->timestamps(); });
Selanjutnya, kita akan membuat model Article
. Untuk melakukan itu, jalankan:
php artisan make:model Article
Kami kemudian membuat pengontrol ArticleController
dengan menjalankan:
php artisan make:controller ArticleController --resource
Selanjutnya, kita akan mengedit file app/Providers/AppServiceProvider.php
dan mengimpor kelas Illuminate\Support\Facades\Schema
dengan menambahkan:
use Illuminate\Support\Facades\Schema
…ke bagian bawah impor di bagian atas file.
Kemudian, dalam fungsi boot
, kita akan menulis:
Schema::defaultStringLength(191);
Setelah semua ini selesai, kita dapat menjalankan:
php artisan migrate
…untuk menerapkan migrasi yang kita buat di atas.
Tutorial Paspor Laravel, Langkah 2: Buat Potongan Middleware yang Diperlukan
Di sini, kami akan menambahkan bagian middleware yang diperlukan agar API berfungsi.
Tanggapan JSON
Bagian pertama yang dibutuhkan adalah middleware ForceJsonResponse
, yang akan mengonversi semua respons ke JSON secara otomatis.
Untuk melakukan ini, jalankan:
php artisan make:middleware ForceJsonResponse
Dan ini adalah fungsi pegangan middleware itu, di App/Http/Middleware/ForceJsonReponse.php
:
public function handle($request, Closure $next) { $request->headers->set('Accept', 'application/json'); return $next($request); }
Selanjutnya, kita akan menambahkan middleware ke file app/Http/Kernel.php
di array $routeMiddleware
:
'json.response' => \App\Http\Middleware\ForceJsonResponse::class,
Kemudian, kita juga akan menambahkannya ke array $middleware
di file yang sama:
\App\Http\Middleware\ForceJsonResponse::class,
Itu akan memastikan bahwa middleware ForceJsonResponse
dijalankan pada setiap permintaan.
CORS (Berbagi Sumber Daya Lintas-Asal)
Untuk mengizinkan konsumen Laravel REST API kami mengaksesnya dari asal yang berbeda, kami harus menyiapkan CORS. Untuk melakukan itu, kita akan membuat sebuah middleware bernama Cors
.
Di terminal atau command prompt, cd
ke direktori root proyek dan jalankan:
php artisan make:middleware Cors
Kemudian, di app/Http/Middleware/Cors.php
, tambahkan kode berikut:
public function handle($request, Closure $next) { return $next($request) ->header('Access-Control-Allow-Origin', '*') ->header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS') ->header('Access-Control-Allow-Headers', 'X-Requested-With, Content-Type, X-Token-Auth, Authorization'); }
Untuk memuat bagian middleware ini, kita perlu menambahkan baris ke array $routeMiddleware
app/Http/Kernel.php
:
'cors' => \App\Http\Middleware\Cors::class,
Juga, kita harus menambahkannya ke array $middleware
seperti yang kita lakukan untuk middleware sebelumnya:
\App\Http\Middleware\Cors::class,
Setelah melakukan itu, kami akan menambahkan grup rute ini ke routes/api.php
:
Route::group(['middleware' => ['cors', 'json.response']], function () { // ... });
Semua rute API kami akan masuk ke fungsi itu, seperti yang akan kita lihat di bawah.
Tutorial Paspor Laravel, Langkah 3: Buat Pengontrol Otentikasi Pengguna untuk API
Sekarang kita ingin membuat pengontrol otentikasi dengan fungsi login
dan register
.
Pertama, kita akan menjalankan:
php artisan make:controller Auth/ApiAuthController
Sekarang kita akan mengimpor beberapa kelas ke file app/Http/Controllers/Auth/ApiAuthController.php
. Kelas-kelas ini akan digunakan dalam pembuatan fungsi login
dan register
. Kami akan mengimpor kelas dengan menambahkan:
use App\User; use Illuminate\Support\Facades\Hash; use Illuminate\Support\Facades\Validator; use Illuminate\Support\Str;
…ke atas pengontrol.
Sekarang, untuk menambahkan otentikasi Laravel API untuk pengguna kami, kami akan membuat fungsi login
, logout
, dan register
(signup) dalam file yang sama.
Fungsi register
akan terlihat seperti ini:
public function register (Request $request) { $validator = Validator::make($request->all(), [ 'name' => 'required|string|max:255', 'email' => 'required|string|email|max:255|unique:users', 'password' => 'required|string|min:6|confirmed', ]); if ($validator->fails()) { return response(['errors'=>$validator->errors()->all()], 422); } $request['password']=Hash::make($request['password']); $request['remember_token'] = Str::random(10); $user = User::create($request->toArray()); $token = $user->createToken('Laravel Password Grant Client')->accessToken; $response = ['token' => $token]; return response($response, 200); }
Fungsi login
seperti ini:
public function login (Request $request) { $validator = Validator::make($request->all(), [ 'email' => 'required|string|email|max:255', 'password' => 'required|string|min:6|confirmed', ]); if ($validator->fails()) { return response(['errors'=>$validator->errors()->all()], 422); } $user = User::where('email', $request->email)->first(); if ($user) { if (Hash::check($request->password, $user->password)) { $token = $user->createToken('Laravel Password Grant Client')->accessToken; $response = ['token' => $token]; return response($response, 200); } else { $response = ["message" => "Password mismatch"]; return response($response, 422); } } else { $response = ["message" =>'User does not exist']; return response($response, 422); } }
Dan akhirnya, fungsi logout
:
public function logout (Request $request) { $token = $request->user()->token(); $token->revoke(); $response = ['message' => 'You have been successfully logged out!']; return response($response, 200); }
Setelah ini, kita perlu menambahkan fungsi login
, register
, dan logout
ke rute kita, yaitu, dalam grup rute yang sudah ada di API:
Route::group(['middleware' => ['cors', 'json.response']], function () { // ... // public routes Route::post('/login', 'Auth\ApiAuthController@login')->name('login.api'); Route::post('/register','Auth\ApiAuthController@register')->name('register.api'); Route::post('/logout', 'Auth\ApiAuthController@logout')->name('logout.api'); // ... });
Terakhir, kita perlu menambahkan sifat HasApiToken
ke model User
. Arahkan ke app/User
dan pastikan Anda memiliki:
use HasApiTokens, Notifiable;
...di atas kelas.
Apa yang Kita Miliki Selama Ini…
Jika kita memulai server aplikasi—yaitu, menjalankan php artisan serve
—dan kemudian mencoba mengirim permintaan GET
ke rute /api/user
, kita akan menerima pesan:
{ "message": "Unauthenticated." }
Ini karena kami tidak diautentikasi untuk mengakses rute itu. Untuk membuat beberapa rute pilihan Anda terlindungi, kami dapat menambahkannya ke routes/api.php
tepat setelah baris Route::post
:
Route::middleware('auth:api')->group(function () { // our routes to be protected will go in here });
Sebelum melanjutkan, kita akan menambahkan rute logout ke auth:api
middleware karena Laravel menggunakan token untuk logout pengguna—token yang tidak dapat diakses dari luar middleware auth:api
. Rute publik kami terlihat seperti ini:
Route::group(['middleware' => ['cors', 'json.response']], function () { // ... // public routes Route::post('/login', 'Auth\ApiAuthController@login')->name('login.api'); Route::post('/register', 'Auth\ApiAuthController@register')->name('register.api'); // ... });
Rute kami yang dilindungi , di sisi lain, terlihat seperti ini:
Route::middleware('auth:api')->group(function () { // our routes to be protected will go in here Route::post('/logout', 'Auth\ApiAuthController@logout')->name('logout.api'); });
Sekarang kita akan menavigasi ke ArticleController
yang kita buat di app/Http/Controllers/ArticleController.php
dan menghapus metode create
dan edit
di kelas itu. Setelah itu, kita akan menambahkan potongan kode berikut, sedikit diedit, ke setiap fungsi yang tersisa:
$response = ['message' => '<function name> function']; return response($response, 200);
Kami akan mengisi <function name>
yang sesuai. Misalnya, fungsi update
akan memiliki ini sebagai tubuhnya:
$response = ['message' => 'update function']; return response($response, 200);
Tes Otentikasi Laravel Manual: Membuat Pengguna
Untuk mendaftarkan pengguna, kami akan mengirimkan permintaan POST
ke /api/register
dengan parameter berikut: name
, email
(yang harus unik), password
, dan password_confirmation
.
Saat pengguna dibuat, API akan mengembalikan token, yang akan kami gunakan dalam permintaan lebih lanjut sebagai sarana kami untuk autentikasi.
Untuk masuk, kami akan mengirimkan permintaan POST
ke /api/login
. Jika kredensial kami benar, kami juga akan mendapatkan token dari API login Laravel kami dengan cara ini.
Token otorisasi yang kami dapatkan kembali dari permintaan ini dapat kami gunakan ketika kami ingin mengakses rute yang dilindungi. Di Postman, tab "Otorisasi" memiliki drop-down di mana jenisnya dapat diatur ke "Pembawa Token," setelah itu token dapat masuk ke bidang token.
Prosesnya sangat mirip dengan Insomnia.
pengguna cURL dapat melakukan hal yang sama dengan meneruskan parameter -H "Authorization: Bearer <token>"
, di mana <token>
adalah token otorisasi yang diberikan dari respons login atau register.
Seperti halnya cURL, jika pengembang berencana untuk menggunakan API menggunakan aksioma atau pustaka semacam itu, mereka dapat menambahkan header Authorization
dengan nilai Bearer <token>
.
Tutorial Paspor Laravel, Langkah 4: Buat Fungsi Reset Kata Sandi
Sekarang setelah otentikasi dasar selesai, saatnya untuk mengatur fungsi pengaturan ulang kata sandi.
Untuk melakukan ini, kita dapat memilih untuk membuat direktori pengontrol api_auth
, membuat pengontrol kustom baru, dan mengimplementasikan fungsi; atau kita bisa mengedit auth controller yang bisa kita generate dengan Laravel. Dalam hal ini, kami akan mengedit pengontrol auth, karena seluruh aplikasi adalah API.

Pertama, kami akan membuat pengontrol auth dengan menjalankan:
composer require laravel/ui php artisan ui vue --auth
Kami akan mengedit kelas di app/Http/Controllers/Auth/ForgotPasswordController.php
, menambahkan dua metode ini:
protected function sendResetLinkResponse(Request $request, $response) { $response = ['message' => "Password reset email sent"]; return response($response, 200); } protected function sendResetLinkFailedResponse(Request $request, $response) { $response = "Email could not be sent to this email address"; return response($response, 500); }
Selanjutnya, kita perlu mengatur pengontrol yang benar-benar mengatur ulang kata sandi, jadi kita akan menavigasi ke app/Http/Controllers/Auth/ResetPasswordController.php
dan menimpa fungsi default seperti ini:
protected function resetPassword($user, $password) { $user->password = Hash::make($password); $user->save(); event(new PasswordReset($user)); } protected function sendResetResponse(Request $request, $response) { $response = ['message' => "Password reset successful"]; return response($response, 200); } protected function sendResetFailedResponse(Request $request, $response) { $response = "Token Invalid"; return response($response, 401); }
Kita juga perlu mengimpor beberapa kelas di controller dengan menambahkan:
use Illuminate\Auth\Events\PasswordReset; use Illuminate\Http\Request; use Illuminate\Support\Facades\Hash;
…ke atas pengontrol.
Kami juga ingin mengubah notifikasi email mana yang digunakan, karena notifikasi email yang disertakan dengan Laravel tidak menggunakan token API untuk otorisasi. Kami dapat membuat yang baru di bawah app/Notifications
dengan menjalankan perintah ini:
php artisan make:notification MailResetPasswordNotification
Kita perlu mengedit file app/Notifications/MailResetPasswordNotification.php
agar terlihat seperti ini:
<?php namespace App\Notifications; use Illuminate\Bus\Queueable; use Illuminate\Notifications\Messages\MailMessage; use Illuminate\Auth\Notifications\ResetPassword; use Illuminate\Support\Facades\Lang; class MailResetPasswordNotification extends ResetPassword { use Queueable; protected $pageUrl; public $token; /** * Create a new notification instance. * * @param $token */ public function __construct($token) { parent::__construct($token); $this->pageUrl = 'localhost:8080'; // we can set whatever we want here, or use .env to set environmental variables } /** * Get the notification's delivery channels. * * @param mixed $notifiable * @return array */ public function via($notifiable) { return ['mail']; } /** * Get the mail representation of the notification. * * @param mixed $notifiable * @return \Illuminate\Notifications\Messages\MailMessage */ public function toMail($notifiable) { if (static::$toMailCallback) { return call_user_func(static::$toMailCallback, $notifiable, $this->token); } return (new MailMessage) ->subject(Lang::getFromJson('Reset application Password')) ->line(Lang::getFromJson('You are receiving this email because we received a password reset request for your account.')) ->action(Lang::getFromJson('Reset Password'), $this->pageUrl."?token=".$this->token) ->line(Lang::getFromJson('This password reset link will expire in :count minutes.', ['count' => config('auth.passwords.users.expire')])) ->line(Lang::getFromJson('If you did not request a password reset, no further action is required.')); } /** * Get the array representation of the notification. * * @param mixed $notifiable * @return array */ public function toArray($notifiable) { return [ // ]; } }
Untuk memanfaatkan notifikasi baru ini, kita perlu mengganti metode sendPasswordResetNotification
yang diwarisi User
dari kelas Authenticatable
. Yang perlu kita lakukan adalah menambahkan ini ke app/User.php
:
public function sendPasswordResetNotification($token) { $this->notify(new \App\Notifications\MailResetPasswordNotification($token)); }
Dengan pengaturan email yang berfungsi dengan baik, pemberitahuan seharusnya berfungsi pada saat ini.
Yang tersisa sekarang adalah kontrol akses pengguna.
Tutorial Paspor Laravel, Langkah 5: Buat Middleware Kontrol Akses
Sebelum kita membuat middleware kontrol akses, kita perlu memperbarui tabel user
agar memiliki kolom bernama type
, yang akan digunakan untuk menentukan level pengguna: tipe 0 adalah pengguna biasa, tipe 1 adalah admin, dan tipe 2 adalah admin super.
Untuk memperbarui tabel user
, kita harus membuat migrasi dengan menjalankan ini:
php artisan make:migration update_users_table_to_include_type --table=users
Dalam file formulir database/migrations/[timestamp]_update_users_table.php
yang baru dibuat, kita harus memperbarui fungsi up
dan down
untuk menambah dan menghapus kolom type
, masing-masing:
public function up() { Schema::table('users', function (Blueprint $table) { $table->integer('type'); }); } /** * Reverse the migrations. * * @return void */ public function down() { Schema::table('users', function (Blueprint $table) { $table->dropIfExists('type'); }); }
Selanjutnya, kita akan menjalankan php artisan migrate
. Setelah ini selesai, kita harus mengedit fungsi register
kita di file ApiAuthController.php
, menambahkan ini tepat sebelum baris dengan $user = User::create($request->toArray());
:
$request['type'] = $request['type'] ? $request['type'] : 0;
Juga, kita perlu menambahkan baris ini ke array $validator
:
'type' => 'integer',
Yang pertama dari dua pengeditan ini akan membuat semua pengguna terdaftar sebagai "pengguna biasa" secara default, yaitu, jika tidak ada jenis pengguna yang dimasukkan.
Middleware Kontrol Akses Itu Sendiri
Sekarang kita berada dalam posisi untuk membuat dua bagian middleware yang digunakan untuk kontrol akses: satu untuk admin dan satu untuk super-admin.
Jadi kita akan menjalankan:
php artisan make:middleware AdminAuth php artisan make:middleware SuperAdminAuth
Pertama, kita akan menavigasi ke app/Http/Middleware/AdminAuth.php
dan import Illuminate\Support\Facades\Auth
, lalu edit fungsi handle
seperti ini:
public function handle($request, Closure $next) { if (Auth::guard('api')->check() && $request->user()->type >= 1) { return $next($request); } else { $message = ["message" => "Permission Denied"]; return response($message, 401); } }
Kita juga perlu mengedit fungsi handle
di app/Http/Middleware/SuperAdminAuth.php
:
public function handle($request, Closure $next) { if (Auth::guard('api')->check() && $request->user()->type >= 2) { return $next($request); } else { $message = ["message" => "Permission Denied"]; return response($message, 401); } }
Anda juga harus mengimpor kelas Auth
di bagian atas kedua file dengan menambahkan:
use Illuminate\Support\Facades\Auth;
…ke dasar impor yang ditemukan di sana.
Untuk menggunakan middleware baru kami, kami akan mereferensikan kedua kelas di kernel—yaitu, di app/Http/Kernel.php
—dengan menambahkan baris berikut ke array $routeMiddleware
:
'api.admin' => \App\Http\Middleware\AdminAuth::class, 'api.superAdmin' => \App\Http\Middleware\SuperAdminAuth::class,
Jika pengembang ingin menggunakan middleware dalam rute tertentu, yang perlu Anda lakukan hanyalah menambahkannya ke fungsi rute seperti ini:
Route::post('route','Controller@method')->middleware('<middleware-name-here>');
<middleware-name-here>
dalam hal ini dapat berupa api.admin
, api.superAdmin
, dll., sebagaimana mestinya.
Itu saja yang diperlukan untuk membuat middleware kita.
Menyatukan Semuanya
Untuk menguji apakah otentikasi dan kontrol akses kami berfungsi, ada beberapa langkah tambahan yang harus dilakukan.
Menguji Otentikasi Laravel dan Kontrol Akses: Langkah 1
Kita perlu memodifikasi fungsi index
ArticleController
dan mendaftarkan rute. (Dalam proyek dunia nyata, kami akan menggunakan PHPUnit dan melakukan ini sebagai bagian dari pengujian otomatis. Di sini, kami menambahkan rute secara manual untuk tujuan pengujian—itu dapat dihapus setelahnya.)
Kami akan menavigasi ke pengontrol ArticleController
di app/Http/Controllers/ArticleController
dan memodifikasi fungsi index
agar terlihat seperti ini:
public function index() { $response = ['message' => 'article index']; return response($response, 200); }
Selanjutnya, kita akan mendaftarkan fungsi dalam sebuah rute dengan membuka file routes/api.php
dan menambahkan ini:
Route::middleware('auth:api')->group(function () { Route::get('/articles', 'ArticleController@index')->name('articles'); });
Menguji Otentikasi Laravel dan Kontrol Akses: Langkah 2
Sekarang kita dapat mencoba mengakses rute tanpa token otentikasi. Kami harus menerima kesalahan otentikasi.
Menguji Otentikasi Laravel dan Kontrol Akses: Langkah 3
Kami juga dapat mencoba mengakses rute yang sama dengan token otorisasi (yang kami dapatkan dari mendaftar atau masuk sebelumnya di artikel ini).
Terkadang, ini dapat menyebabkan kesalahan yang mirip dengan ini:
Unknown column 'api_token' in 'where clause' (SQL: select * from `users` where `api_token` = ...
Jika ini terjadi, pengembang harus memastikan telah menjalankan migrasi Paspor dan ['guards']['api']['driver']
disetel ke passport
di config/auth.php
:
'guards' => [ 'web' => [ 'driver' => 'session', 'provider' => 'users', ], 'api' => [ 'driver' => 'passport', 'provider' => 'users', ], ],
Setelah itu, cache konfigurasi juga perlu diperbarui.
Setelah itu diperbaiki, kita harus memiliki akses ke rute.
Menguji Otentikasi Laravel dan Kontrol Akses: Langkah 4
Saatnya untuk menguji kontrol akses. Mari tambahkan ->middleware('api.admin')
ke rute artikel, sehingga terlihat seperti ini:
Route::get('/articles', 'ArticleController@index')->middleware('api.admin')->name('articles');
Kami membuatnya sedemikian rupa sehingga pengguna yang baru dibuat secara otomatis ditetapkan tipe 0, seperti yang dapat kita lihat melalui rute api/user
.
Karena itu, kita harus mendapatkan kesalahan saat mencoba mengakses titik akhir articles
sebagai pengguna tersebut.
Untuk tujuan pengujian, mari ubah pengguna di database menjadi type
1. Setelah memverifikasi perubahan itu melalui rute api/user
lagi, kita siap untuk mencoba lagi untuk GET
rute /articles/
.
Ini bekerja dengan sempurna.
Pengembang yang membuat aplikasi yang lebih kompleks harus memperhatikan bahwa kontrol akses yang tepat tidak akan sesederhana ini. Dalam hal ini, aplikasi pihak ketiga lainnya atau gerbang dan kebijakan Laravel dapat digunakan untuk mengimplementasikan kontrol akses pengguna khusus. Di bagian kedua dari seri ini, kita akan melihat solusi kontrol akses yang lebih kuat dan fleksibel.
Otentikasi Laravel API: Apa yang Kami Pelajari
Dalam tutorial Paspor Laravel ini, kami membahas:
- Membuat pengontrol dan model dummy agar memiliki sesuatu untuk digunakan saat menguji contoh Laravel Passport kami.
- Membuat middleware yang diperlukan untuk membuat API kami berjalan dengan lancar, menangani CORS dan memaksa API untuk selalu mengembalikan respons JSON.
- Menyiapkan otentikasi API Laravel dasar: mendaftar, masuk, dan keluar.
- Menyiapkan fungsionalitas "reset kata sandi" berdasarkan default Laravel.
- Membuat middleware kontrol akses untuk menambahkan tingkat izin otorisasi pengguna ke rute yang berbeda.
Ini adalah keterampilan penting bagi siapa saja yang bekerja di bidang layanan pengembangan Laravel. Pembaca akan menemukan hasil akhir dalam repo GitHub ini dan sekarang harus berada pada posisi yang baik untuk mengimplementasikan otentikasi dengan Laravel. Kami menantikan komentar di bawah ini.