Single Sign On (SSO) Laravel Client dengan OAuth2

Panduan lengkap membuat Single Sign-On (SSO) laravel client menggunakan OAuth2 untuk autentikasi yang lebih aman.
Single Sign On (SSO) Laravel Client dengan OAuth2

Buat Project

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 sso-client
cd sso-client

Buat Controller

Controller bertanggung jawab untuk menangani logika dan memastikan dapat terhubung dengan sso server untuk proses autentikasi.

php artisan make:controller AuthController
<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Str;

class AuthController extends Controller
{
    public function login(Request $request)
    {
        try {
            $request->session()->put('state', $state = Str::random(40));

            $query = http_build_query([
                'client_id'     => '9dcf9271-a2e3-41a7-8ad3-114c2e388687',
                'redirect_uri'  => 'http://127.0.0.1:8001/auth/callback',
                'response_type' => 'code',
                'scope'         => 'view-user view-permission',
                'state'         => $state,
            ]);

            return redirect('http://127.0.0.1:8000/oauth/authorize?' . $query);
        } catch (\Exception $e) {
            Log::error('auth: ' . $e->getMessage());
            return redirect('/')->with('error', 'Terjadi kesalahan pada server.');
        }
    }

    public function callback(Request $request)
    {
        $state = $request->session()->pull('state');

        if (!strlen($state) || $state !== $request->state) {
            return redirect('/')->with('error', 'Terjadi kesalahan pada server.');
        }

        try {
            $response = Http::asForm()->post('http://127.0.0.1:8000/oauth/token', [
                'grant_type'    => 'authorization_code',
                'client_id'     => '9dcf9271-a2e3-41a7-8ad3-114c2e388687',
                'client_secret' => 'cxQRd00WHe8U4anWrMqVDEss6zdHT8PID8Rh2D79',
                'redirect_uri'  => 'http://127.0.0.1:8001/auth/callback',
                'code'          => $request->code,
            ]);

            if ($response->failed()) {
                return redirect('/')->with('error', 'Terjadi kesalahan pada server.');
            }

            $user = Http::withHeaders([
                'Accept' => 'application/json',
                'Authorization' => 'Bearer ' . $response['access_token'],
            ])->get('http://127.0.0.1:8000/api/user');

            $permission = Http::withHeaders([
                'Accept' => 'application/json',
                'Authorization' => 'Bearer ' . $response['access_token'],
            ])->get('http://127.0.0.1:8000/api/permission');

            $request->session()->put([
                'token'      => $response->json(),
                'user'       => $user->json(),
                'permission' => $permission->json(),
            ]);

            return redirect()->intended('/home');
        } catch (\Exception $e) {
            Log::error('auth.callback: ' . $e->getMessage());
            return redirect('/')->with('error', 'Terjadi kesalahan pada server.');
        }
    }

    public function logout(Request $request)
    {
        try {
            $token = session('token.access_token');

            if ($token) {
                Http::withToken($token)->post('http://127.0.0.1:8000/api/logout');
            }

            $request->session()->invalidate();
            $request->session()->regenerateToken();

            return redirect('/');
        } catch (\Exception $e) {
            Log::error('auth.logout: ' . $e->getMessage());
            return redirect('/')->with('error', 'Terjadi kesalahan pada server.');
        }
    }
}

➔ Gantilah http://127.0.0.1:8000 dengan url SSO Server Anda.

➔ Gantilah http://127.0.0.1:8001 dengan url SSO Client Anda.

➔ Gantilah 9dcf9271-a2e3-41a7-8ad3-114c2e388687 dengan Client ID Anda.

➔ Gantilah cxQRd00WHe8U4anWrMqVDEss6zdHT8PID8Rh2D79 dengan Client Secret Anda.

Posting Terkait

Buat Middleware

Membuat middleware untuk mengecek apakah token tersedia dan valid serta memeriksa apakah pengguna memiliki permission tertentu.

php artisan make:middleware CheckSSOAuth
php artisan make:middleware CheckPermission

Daftarkan middleware di app/bootstrap/app.php: Tambahkan ke array withMiddleware.

$middleware->alias([
    'sso.auth' => \App\Http\Middleware\CheckSSOAuth::class,
    'permission' => \App\Http\Middleware\CheckPermission::class,
]);
<?php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
use Symfony\Component\HttpFoundation\Response;
use Illuminate\Support\Facades\Session;

class CheckSSOAuth
{
    /**
     * Handle an incoming request.
     *
     * @param  \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response)  $next
     */
    public function handle($request, Closure $next)
    {
        if (!Session::has('token.access_token')) {
            Log::info('auth: user not logged in');
            return redirect('/')->with('error', 'Terjadi kesalahan pada server. Silakan coba lagi.');
        }

        return $next($request);
    }
}
<?php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;

class CheckPermission
{
    /**
     * Handle an incoming request.
     *
     * @param  \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response)  $next
     */
    public function handle(Request $request, Closure $next, $permission)
    {
        $permissions = session('permission', []);

        if (!in_array($permission, $permissions)) {
            return response()->json([
                'status' => false,
                'message' => 'You do not have permission to access this resource',
            ], Response::HTTP_FORBIDDEN);
        }

        return $next($request);
    }
}

Buat View

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

php artisan make:view home
<!doctype html>
<html lang="en">
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
        <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">
        <link href="https://fonts.googleapis.com/css2?family=Quicksand:wght@300;400;500;600&display=swap" rel="stylesheet">
        <title>{{ $title ?? config('app.name') }}</title>
        <style>
            body {
                background: lightgray;
                font-family: 'Quicksand', sans-serif
            }
        </style>
    </head>

    <body>
        <div class="container mt-5">
            <div class="row justify-content-center">
                <div class="col-md-10">
                    <div class="card border-0 shadow rounded">
                        <div class="card-body">
                            <h1>SSO Client</h1>
                            Selamat Datang {{ session('user.name') }}</strong>
                            <hr>
                            <a href="/manage-slik">manage-slik</a> | <a href="/manage-kredit">manage-kredit</a>
                            <hr>
                            <a href="{{ route('logout') }}" style="cursor: pointer" onclick="event.preventDefault();
                    document.getElementById('logout-form').submit();" class="btn btn-md btn-primary">LOGOUT</a>
                            <form id="logout-form" action="{{ route('logout') }}" method="POST" style="display: none;">
                                @csrf
                            </form>
                        </div>
                    </div>
                </div>
            </div>
        </div>

        <script src="https://code.jquery.com/jquery-3.5.1.slim.min.js"></script>
        <script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.1/dist/umd/popper.min.js"></script>
        <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js"></script>
    </body>
</html>

Inisialisasi Route

Menyiapkan rute untuk menangani permintaan autentikasi. Rute ini akan mengarahkan pengguna ke controller yang telah dibuat sebelumnya untuk memproses data.

<?php

use App\Http\Controllers\AuthController;
use Illuminate\Support\Facades\Route;

Route::get('/', function () {
    return view('welcome');
});

Route::get('/auth', [AuthController::class, 'login'])->name('login');
Route::get('/auth/callback', [AuthController::class, 'callback'])->name('auth.callback');

Route::middleware('sso.auth')->group(function () {
    Route::get('/home', function () {
        return view('home');
    })->name('home');

    Route::post('/logout', [AuthController::class, 'logout'])->name('logout');
});

Lakukan Uji Coba

Cobalah lakukan pengujian proses login untuk memastikan aplikasi berfungsi sesuai harapan tanpa masalah.

php artisan server

Posting Komentar