Для розробників безпека додатків і API є одним із найважливіших аспектів. Проте часто про це починають думати надто пізно в процесі проєктування, або ж змушені використовувати застарілі рішення, приймаючи неприємні для себе рішення. Саме тому я постійно запитую себе: чи є альтернативні способи розв'язання поширених проблем, щоб зробити мої рішення більш стійкими та розширювальними, враховуючи постійно змінювані потреби користувачів? У світі PHP і Laravel це питання завжди актуальне, а FusionAuth пропонує саме те, що потрібно для автентифікації.
У цій статті я на прикладі покажу, як використати FusionAuth у Laravel-додатку, розгорнутому на Elastic Container Service AWS за допомогою Cloud Development Kit.
Перед початком зазначу, що FusionAuth спонсорував мене для експериментів із їхнім продуктом та звіту про результати. Вони отримали мою увагу, проте не мою думку. Ось мій неупереджений погляд на досвід розробника при створенні Laravel-додатку з використанням FusionAuth для автентифікації.
Розпочинаючи з прикладів рішень, я завжди віддаю перевагу починати з кінцевого результату і лише потім рухатись назад. Це стосується не лише написання статті, а й формування структури, яку я хочу презентувати. Я віддаю перевагу AWS, оскільки маю понад 10 років досвіду роботи на їхній платформі. Проте, краще один раз побачити, ніж сто разів почути.
У цій архітектурній схемі ключові компоненти такі:
З дизайном готово, давайте поглянемо на рішення по порядку!
Я швидко пройдуся по налаштуванню додатку та структурі проєкту, оскільки хочу більше зосередитися на Socialite, налаштуванні FusionAuth і розгортанні на AWS.
Я не робив нічого особливого при створенні Laravel-додатку. Все розпочалося з команди:
laravel new fusionauth-app
Надалі я відповів на запитання налаштування, обравши PHPUnit
для тестування, SQLite
для бази даних і Vite для фронтенд-інструментів. Ця конфігурація створила структуру проєкту з відповідними каталогами та файлами.
Тепер можемо додати Socialite.
Socialite дозволяє легко інтегрувати OAuth-автентифікацію з різними провайдерами, такими як Facebook, GitHub та інші. Він обробляє більшість рутинного коду, якого багато хто з нас хоче уникнути. За допомогою Socialite я можу аутентифікувати користувачів через різних провайдерів, включаючи FusionAuth. Це дає можливість обмежувати доступ до мого додатку.
Щоб підключити FusionAuth, виконайте наступні кроки.
Крок 1: Додати Socialite до проєкту.
# Додаємо залежність Socialite
composer require laravel/socialite
# Додаємо провайдер FusionAuth
composer require socialiteproviders/fusionauth
Крок 2: Встановити змінні середовища в файлі .env
та надати значення у config/services.php
.
# .env файл
# Налаштування FusionAuth
FUSIONAUTH_CLIENT_ID=
FUSIONAUTH_CLIENT_SECRET=<Секрет клієнта FusionAuth>
FUSIONAUTH_BASE_URL=<Базовий URL FusionAuth>
FUSIONAUTH_TENANT_ID=
FUSIONAUTH_REDIRECT_URI=
Ці змінні потім використовуються в services.php
для налаштування провайдера Socialite FusionAuth.
return [
'fusionauth' => [
'client_id' => env('FUSIONAUTH_CLIENT_ID'),
'client_secret' => env('FUSIONAUTH_CLIENT_SECRET'),
'redirect' => env('FUSIONAUTH_REDIRECT_URI'),
'base_url' => env('FUSIONAUTH_BASE_URL'),
'tenant_id' => env('FUSIONAUTH_TENANT_ID'),
]
];
Крок 3: Створити маршрути для перенаправлення користувача до FusionAuth та обробки зворотного зв'язку. Потрібен Controller
з двома функціями.
Перша функція, redirectToFusionAuth
, виконує перенаправлення до FusionAuth. Друга функція, callbackFusionAuth
, обробляє повернення з FusionAuth, отримуючи дані користувача та зберігаючи їх у локальній таблиці SQLite.
<?php
namespace App\Http\Controllers;
use App\Models\User;
use Illuminate\Support\Facades\Auth;
use Laravel\Socialite\Facades\Socialite;
class FusionAuthLoginController extends Controller
{
public function redirectToFusionAuth()
{
return Socialite::driver('fusionauth')->redirect();
}
public function callbackFusionAuth()
{
$user = Socialite::driver('fusionauth')->user();
$user = User::updateOrCreate([
'fusionauth_id' => $user->id,
], [
'name' => $user->name,
'email' => $user->email,
'given_name' => $user->user['given_name'],
'family_name' => $user->user['family_name'],
'fusionauth_access_token' => $user->token,
]);
Auth::login($user);
return redirect('/profile');
}
}
Для довідки, ось мій клас User
.
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
class User extends Authenticatable
{
use HasFactory;
protected $fillable = [
'name',
'email',
'given_name',
'family_name',
'fusionauth_id',
'fusionauth_access_token',
];
protected $hidden = ['password', 'remember_token'];
}
Після того, як користувач увійшов, я можу використовувати перевірку доступу на рівні сторінки або API, щоб контролювати виконання операцій. Це робиться традиційним способом у Laravel за допомогою Gates
або Policies
.
Отже, у мене вже є Laravel-додаток з установленим плагіном Socialite, який успішно пов'язаний з FusionAuth. Тепер привернемо увагу до FusionAuth.
FusionAuth можна використовувати як на власних серверах, так і на їхньому хостингу. Вони пропонують безліч рішень. Я вирішив зосередитися на розробницькому досвіді з FusionAuth, тому скористався їхнім хостингом.
FusionAuth — це повноцінний постачальник OAuth 2.0 та OIDC. Ці два поняття часто плутають, але вони різні: OAuth 2.0 використовується для авторизації, а OIDC — для аутентифікації.
Це головний екран програми в FusionAuth, де я налаштував свій Laravel-додаток, зазначивши необхідні налаштування, включаючи Authorized Redirect URLs
.
Тут ви знайдете знайомі налаштування для OAuth та OIDC. Ось швидкий огляд!
Ключові кінцеві точки
Обсяги
FusionAuth пропонує багато можливостей для налаштувань, включаючи кастомізацію JWT, а також інтеграцію SAML та можливість самостійної реєстрації користувачів.
Я не можу охопити всі можливості, які доступні в меню з навігацією, але хочу виділити звітність. Я часто отримую запитання на кшталт "Скільки активних користувачів у нас?" або "Скільки було реєстрацій цього місяця?" FusionAuth має для цього розділ звітів.
Отже, у мене вже розгорнута FusionAuth та Laravel-додаток, зв’язаний із FusionAuth через Socialite. Залишилося розгорнути додаток на AWS.
Мій Laravel-додаток працює в AWS. Я трохи налаштував стартову сторінку, і тепер вона запущена під HTTPS на Elastic Container Service (ECS) AWS. Це означає, що я упакував його в Docker-контейнер. Чи використовував я Sail? CloudFormation? Давайте дізнаємось!
Існує безліч варіантів для розгортання інфраструктури та додатків в AWS. Я міг би використовувати CloudFormation, Terraform або Pulumi, але обрав AWS Cloud Development Kit (CDK) — зазвичай на TypeScript.
CDK дозволяє створювати класи, які відображають представлення CloudFormation, і я звик до його документації, завдяки чому все виглядає зрозуміло і знайоме на ділянці інфраструктури.
Згадаймо архітектуру рішення. Потрібно створити публічні та приватні мережі, віртуальні приватні хмари, баланси навантаження, кластер ECS і так далі.
- app-infra/
- infra/
Директорія infra
містить базові ресурси — усю інфраструктуру поза Fargate. Кожен зі створюваних ресурсів підтримує розгортання Laravel-додатку.
Наприклад, створення ECS кластера виглядає так:
let cluster = new Cluster(
scope,
`EcsCluster`,
{
clusterName: `DemoCluster`,
vpc: props.vpc
}
);
Повний робочий приклад доступний на GitHub у кінці статті. Однак важливо зазначити, що для хостингу додатку в AWS ECS залучені такі сервіси:
Для всього цього потрібно повернутись до Laravel-додатку. Як я вже згадував, програма упакована в Docker-контейнер з Nginx у ролі зворотного проксі, який належно обробляє статичний контент. У каталозі проєкту знаходиться docker/
з entrypoint.sh
, що запускає Nginx та PHP.
#!/usr/bin/env bash
service nginx start
php artisan migrate --force
php artisan storage:link
php artisan optimize:clear
php artisan optimize
php-fpm
Там є ще default.conf
, що містить конфігураційні параметри для Nginx.
server {
listen 80 default_server;
server_name localhost;
root /var/www/public;
location ~ \.php$ {
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}
location / {
try_files $uri $uri/ /index.php?$query_string;
}
}
CloudFormation в AWS розглядає деплойменти як "Stacks", що містять ресурси для розгортання. Кожна з директорій при створенні свого стеку має власні ресурси для керування. Розгортання відбувається на простому за допомогою:
cd infra
cdk deploy
#
cd ../app-infra
cdk deploy
Це був насичений огляд Laravel та Socialite, FusionAuth і AWS CDK. Але що в результаті всіх цих зусиль? У мене тепер є додаток, що завантажується з ECS, автентифікує користувача за допомогою FusionAuth і показує просту сторінку профілю з даними, які зберігаються в FusionAuth. Ця інформація містить мою електронну пошту, дату народження, ім'я, прізвище, а також не відображувану часову зону.
При переході до свого додатку я можу натиснути "Увійти" у верхньому правому куті, і мене перенаправить на сторінку для введення облікових даних.
Після успішної верифікації я потраплю на сторінку профілю, де бачу свої дані.
Аутентифікація та авторизація рідко бувають привабливими аспектами рішень. Коли щось йде не так, це швидше привабливе іншим, а не дизайнерським. Тому я шукаю рішення, яке є надійним, гнучким і розширювальним. Хоча я ще не тестував FusionAuth у продуктивному масштабі, сподіваюся, ви зрозуміли з цієї статті, що воно дуже налаштоване та розширюване. Я також помітив, що модель ціноутворення FusionAuth є привабливою, а підтримка відповідає потребам, чи це цілодобовий сервіс, чи внутрішній проєкт протягом робочого часу.
Мені сподобалася гнучкість у налаштуванні. Досвід адміністратора виявився корисним, всі потрібні мені налаштування на місці. Інтеграція з PHP та Laravel була надзвичайно простою. Я просто підключив Socialite, встановив змінні, написав невеликий Controller
— і все запрацювало.
Також варто відзначити надзвичайну документацію, яка допомогла мені швидко освоїти FusionAuth та зрозуміти концепції, пов'язані з розгортанням.
Це радше загальна проблема, ніж конкретна для FusionAuth. Коли я думаю про PHP-додатки, не уявляю собі контейнеризацію чи Kubernetes. Я б вважав за краще налаштувати функціонал на рівні одного застосунку. Документація FusionAuth чудова, але я не зумів реалізувати налаштування самостійно. Тому я вирішив скористатися їхнім хостингом, щоб зосередитися на розробці, а не на налаштуваннях інфраструктури.
Можливо, якби були шаблони для швидкого розгортання в AWS з попередніми налаштуваннями, це б пришвидшило процес.
Створення власної автентифікації не є рішучим кроком у наші часи. Якщо ви плануєте розширення, вам точно варто інвестувати в рішення третіх осіб. У цьому сегменті є конкуренція, проте мій досвід з FusionAuth під час написання статті переконує мене, що, якби я створював новий проєкт, звернувся б до FusionAuth.
Цей продукт легко управляти, має велику налаштованість та безліч можливостей для розширення. Коли я працюю з Laravel, інтеграція з Socialite проходить стає простою. Паралельно з AWS я впевнений, що FusionAuth стане надійним і потужним інструментом для моїх проєктів.
Я посилався на безліч коду, тому ось репозиторій GitHub, який ви можете клонувати, побудувати та розгорнути самостійно.
Дякую за увагу та успіхів у розробці!