Single Sign On (SSO) Server dengan OAuth2 Laravel Passport

OAuth2 digunakan untuk proses autentikasi dan otorisasi oleh produk dari pihak ketiga yang menggunakan layanan autentikasi dari produk lain.
Single Sign On (SSO) Server dengan OAuth2 Laravel Passport

Pemberitahuan
Artikel ini sedang dalam proses penulisan, mengingat banyaknya kode yang perlu disertakan. Kami akan menyelesaikannya secepat mungkin. Terima kasih.

Buat Project

Langkah pertama adalah membuat proyek Laravel baru. Anda perlu menyiapkan lingkungan pengembangan dengan menginstal Composer dan PHP terlebih dahulu, kemudian membuat proyek baru menggunakan perintah yang sesuai.

composer create-project laravel/laravel:^10.0 sso_server
cd sso_server

Installasi Passport

Proses instalasi Passport dimulai dengan menginstal paket passport melalui Composer, kemudian menjalankan perintah untuk migrasi database dan membuat enkripsi key untuk keamanan.

composer require laravel/passport
php artisan migrate
php artisan passport:install --uuids
php artisan vendor:publish --tag=passport-views

Inisialisasi Passport

Berikutnya adalah implementasi fungsi-fungsi untuk berinteraksi dengan Passport dan mengonfigurasi kebutuhan untuk OAuth2.

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Laravel\Passport\HasApiTokens;
 
class User extends Authenticatable
{
    use HasApiTokens, HasFactory, Notifiable;
}
'guards' => [
    'web' => [
        'driver' => 'session',
        'provider' => 'users',
    ],
 
    'api' => [
        'driver' => 'passport',
        'provider' => 'users',
    ],
],
<?php

namespace App\Providers;

// use Illuminate\Support\Facades\Gate;
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
use Laravel\Passport\Passport;
use App\Models\Passport as ModelsPassport;

class AuthServiceProvider extends ServiceProvider
{
    /**
     * The model to policy mappings for the application.
     *
     * @var array<class-string, class-string>
     */
    protected $policies = [
        //
    ];

    /**
     * Register any authentication / authorization services.
     */
    public function boot(): void
    {
        Passport::tokensExpireIn(now()->addDays(1));
        Passport::refreshTokensExpireIn(now()->addDays(30));
        Passport::personalAccessTokensExpireIn(now()->addMonths(6));

        Passport::tokensCan([
            'view-user' => 'access user',
        ]);

        Passport::useClientModel(ModelsPassport::class);
    }
}
protected $middlewareAliases = [
    // ...
    'scopes' => \Laravel\Passport\Http\Middleware\CheckScopes::class,
    'scope' => \Laravel\Passport\Http\Middleware\CheckForAnyScope::class,
];

Buat Model

Untuk integrasi Passport dengan Laravel, Anda dapat membuat model khusus yang mewarisi dari model Client milik Laravel Passport.

php artisan make:model Passport
<?php

namespace App\Models;

use Laravel\Passport\Client;

class Passport extends Client
{
    public function skipsAuthorization()
    {
        return false;
    }
}

Buat Controller

Controller bertanggung jawab untuk menangani logika autentikasi dan alur pengguna. Anda perlu membuat controller yang akan menangani login, logout, dan fitur lainnya, serta menghubungkan aplikasi dengan sistem OAuth2 untuk autentikasi.

Buat View

Anda bisa menyesuaikan tampilan ini dengan kebutuhan aplikasi Anda agar sesuai dengan tema dan pengalaman pengguna yang diinginkan.

@extends('layouts.auth')
@section('title', 'Authorization')

@section('content')
<div class="content-wrapper">
    <section class="content center-box">
        <div class="box border-0" style="width: 30%;">
            <div class="box-header bg-blue radius-lr-3">
                <h3 class="box-title">Permintaan Otorisasi</h3>
            </div>
            <div class="box-body">
                <p>
                    <strong>{{ $client->name }}</strong> meminta izin untuk mengakses akun Anda.
                    @if (count($scopes) > 0)
                    Aplikasi ini meminta izin untuk mengakses informasi berikut:
                <ul class="mt--5">
                    @foreach ($scopes as $scope)
                    <li>{{ $scope->description }}</li>
                    @endforeach
                </ul>
                @endif
                </p>

                <div class="box-footer box-auth mb--10">
                    <!-- Authorize Button -->
                    <form method="post" action="{{ route('passport.authorizations.approve') }}">
                        @csrf

                        <input type="hidden" name="state" value="{{ $request->state }}">
                        <input type="hidden" name="client_id" value="{{ $client->getKey() }}">
                        <input type="hidden" name="auth_token" value="{{ $authToken }}">
                        <button type="submit" class="btn btn-success btn-approve">Izinkan</button>
                    </form>

                    <!-- Cancel Button -->
                    <form method="post" action="{{ route('passport.authorizations.deny') }}">
                        @csrf
                        @method('DELETE')

                        <input type="hidden" name="state" value="{{ $request->state }}">
                        <input type="hidden" name="client_id" value="{{ $client->getKey() }}">
                        <input type="hidden" name="auth_token" value="{{ $authToken }}">
                        <button class="btn btn-danger">Tolak</button>
                    </form>
                </div>
            </div>
        </div>
    </section>
</div>
@endsection

Inisialisasi Route

Menyiapkan rute untuk menangani permintaan autentikasi yang masuk, seperti rute untuk login, logout, dan proses registrasi. Rute ini akan mengarahkan pengguna ke controller yang telah dibuat sebelumnya untuk memproses data.

<?php

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

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

Route::middleware('auth:api')->get('/logout-sso', function (Request $request) {
    $user = $request->user();
    $accessToken = $user->token();

    DB::table('oauth_refresh_tokens')->where('access_token_id', $accessToken->id)->delete();

    $accessToken->delete();

    return response()->json([
            'message' => 'Revoked',
    ]);
});
<?php

use Illuminate\Support\Facades\Route;

Route::get('/', function () {
    return redirect()->route('login');
});

Route::get('/login', [App\Http\Controllers\AuthController::class, 'login'])->name('login');
Route::post('/login', [App\Http\Controllers\AuthController::class, 'authenticate'])->name('authenticate');
Route::post('/logout', [App\Http\Controllers\AuthController::class, 'logout'])->name('logout')->middleware('auth');

Route::middleware(['auth'])->group(function () {
    Route::get('/dashboard', function () {
        return view('dashboard');
    });

    Route::get('/user', [App\Http\Controllers\UserController::class, 'index'])->name('user.index');
    Route::get('/user/create', [App\Http\Controllers\UserController::class, 'create'])->name('user.create');
    Route::post('/user', [App\Http\Controllers\UserController::class, 'store'])->name('user.store');
    Route::get('/user/{user}', [App\Http\Controllers\UserController::class, 'show'])->name('user.show');
    Route::put('/user/{user}', [App\Http\Controllers\UserController::class, 'update'])->name('user.update');
    Route::delete('/user/{user}', [App\Http\Controllers\UserController::class, 'destroy'])->name('user.destroy');

    Route::get('/client', [App\Http\Controllers\ClientController::class, 'index'])->name('client.index');
    Route::get('/client/create', [App\Http\Controllers\ClientController::class, 'create'])->name('client.create');
    Route::post('/client', [App\Http\Controllers\ClientController::class, 'store'])->name('client.store');
    Route::get('/client/{client}', [App\Http\Controllers\ClientController::class, 'show'])->name('client.show');
    Route::put('/client/{client}', [App\Http\Controllers\ClientController::class, 'update'])->name('client.update');
    Route::delete('/client/{client}', [App\Http\Controllers\ClientController::class, 'destroy'])->name('client.destroy');
});

Lakukan Uji Coba

Setelah implementasi selesai, langkah terakhir adalah melakukan pengujian untuk memastikan bahwa sistem autentikasi berjalan dengan lancar. Cobalah membaut user dan client untuk memastikan aplikasi berfungsi sesuai harapan tanpa masalah.

Posting Komentar