Felhasználói hitelesítés - Jetstream - 1. rész: Alapok, telepítés, első használat

Attila | 2023. 01. 15. 12:50 | Olvasási idő: 6 perc

Címkék: #Jetstream #Laravel #Laravel 9 #Sail #Tailwind #Telepítés (Installation)

Visszatérünk a felhasználói hitelesítés témaköréhez. Elég sok altémáját kiveséztük már, miközben ismerkedtünk a Laravel Breeze-zel, most viszont egy másik hitelesítési eszközzel kezdünk foglalkozni, a Laravel Jetstream-mel. Ez rendelkezésünkre bocsátja mindazt, amit a Breeze is tud, viszont annál többet is ad nekünk. Kezdjük meg a munkát vele és vegyük végig a lehetőségeinket.
laravel-jetstream

Bevezetés

A Laravel Jetstream egy szép felhasználói felületen keresztül biztosítja a számunkra a felhasználói hitelesítés lehetőségét. Ha tudjuk, hogy egy következő alkalmazásunkban szükség lesz felhasználói hitelesítési folyamatokra, funkciókra, komplexebb megoldásokra, akkor mindenképpen érdemes már a projekt fejlesztésének indításakor telepíteni és beüzemelni a Laravel Jetstream-et. Ez biztosítani fogja a számunkra a felhasználói regisztrációt, be- és kijelentkezést, e-mail-es megerősítést, két-faktorú azonosítást, felhasználói munkamenet (session) kezelését, csapat / szerepkör menedzselését és még több minden egyéb funkcionalitást is.

A Tailwind CSS keretrendszer biztosítja a számunkra a szép felhasználói felületet, úgyhogy aki mélyebben szeretne megismerkedni a Jetstream-mel, az mindenképpen térképezze fel a részletes működését. (Én korábban leginkább Bootstrap CSS keretrendszert használtam. A két keretrendszer dokumentációjának felületes összehasonlításával azt tudom leszűrni, hogy az alapvető háttérgondolat hasonló, úgyhogy akinek van Bootstrap-es tapasztalata, az nagyobb magabiztossággal indulhat neki a Tailwind megismerésének. A dokumentációja mindenképpen jó kiindulási pont, úgyhogy kezdők se ijedjenek meg a használatáról, talán majd én is fogok róla írni részletesebben...)

Ezekután két irányba indulhatunk el, amikor a kliens oldali keretrendszerek között dönthetünk (az irányok főleg a template nyelv használatában különböznek):

  1. Livewire + Blade
  2. Inertia.js + Vue.js

Mindkét irányvonal megfelelő és csak tőlünk függ, hogy melyiket választjuk, mert mindkettővel szép és hatékonyan működő megoldásokat tudunk megvalósítani. Viszont mindkét tématerület egy-egy jó nagy háttéranyagot és tudást igényel... viszont van mindkettőhöz videós tanfolyam, amikből lehet tanulni:

  1. Livewire videósorozat
  2. Inertia videósorozat

A jó hírem az, hogy ha nem is ismerjük ezeket, csak szeretnénk egy jól működő, szép, komplett hitelesítési rendszert használni a Laravel webalkalmazásunkban, akkor a Jetstream tökéletesen alkalmas erre, hiszen már alapból rengeteg mindent ad nekünk, amit ebben a bejegyzésben át is nézünk. A későbbiekben én is biztos vissza fogok majd térni ezekhez a fenti technológiákhoz, de most egyelőre a Jetstream-re koncentrálok.

Kiinduló weboldalunk, ahol bővebben is ismerkedhetünk a Jetstream-mel: https://jetstream.laravel.com/

Továbbra is Docker-alapon dolgozunk, ebben a Laravel Sail segít nekünk, érdemes elindítani a futtatását. (Ha nem emlékeznénk rá, akkor az előző bejegyzést érdemes megnézni hozzá.)

Induló projektünk fenn van a Github-on: https://github.com/gludovatza/sail-jetstream


Telepítés

Jöhet a telepítés! Hajtsuk végre a következő utasításokat:

composer require laravel/jetstream

Talán először a Livewire + Blade választás egy kicsit egyszerűbbnek tűnhet, úgyhogy ezt az utat fogom bejárni elsőre:

php artisan jetstream:install livewire --teams

Ezzel az utasítással "csapatokat" (csoportokat, szerepköröket) is tudok majd hozzárendelni a felhasználókhoz. A parancs futtatásának hatására települtek a jetstream, livewire és a hozzájuk kapcsolódó (függőségek) csomagjai is. Települtek még a kliens oldali függőségek, továbbá még létrejöttek a migrációs fájlok is. Itt azonban még egy migráció hátravan, de előtte megmutatom, hogy nálam hogyan néz most ki az .env fájl releváns része, ami alapján akar csatlakozni a konténerben futó MySQL szerver szolgáltatáshoz:

DB_CONNECTION=mysql
DB_HOST=mysql
DB_PORT=3306
DB_DATABASE=sailjetstream
DB_USERNAME=root
DB_PASSWORD=

A Host-ra hívnám fel mindenképpen a figyelmet, mert ez nem a megszokott 127.0.0.1, hanem egyszerűen mysql. Előfordulhat, hogy nálatok a username sail a password pedig password, ezt mindenki maga tudja ellenőrizni, amikor rácsatlakozik például a MySQL Workbench alkalmazással a kiszolgálójára. Ha működik a kapcsolódás a saját paramétereinkkel, akkor következhet a migráció:

php artisan migrate

Futtatva az alkalmazást, jobb felül megjelennek a "Log in" és a "Register" linkek az oldalon:

Ha rámegyünk a regisztrációs linkre, akkor már láthatjuk is, hogy a megjelenik a regisztrációs űrlap felett a Jetstream logója:

Regisztráljunk is be egy felhasználót. A validáció, vagyis a mezők helyességének ellenőrzése szerencsére itt már alapértelmezetten működik, tehát például, ha a jelszónak 8 karakternél rövidebbet szeretnénk beállítani, akkor jelezni fog a "Register" gomb megnyomása után, hogy túl rövid a jelszavunk. Ha mindent helyesen adtunk meg, akkor megtörtént a regisztráció és automatikusan be is jelentkeztet minket a rendszer:

A Jetstream vezérlőpultja fogad minket, jobb felül pedig látható, hogy milyen felhasználóval vagyok bejelentkezve, plusz még egy csapatom is van! Hát ez így eléggé szuper!

A Jetstream számos beállítási lehetőséget nyújt a számunkra alapértelmezetten, ezek a felhasználónkhoz és a csapatunkhoz kötődnek. Nézzük meg először a felhasználói profilunkhoz kapcsolódó beállításainkat, majd a csapatosakat.


Felhasználói funkcionalitások, beállítások

A nevünkön kattintva lenyílik a helyi menü és kiválaszthatjuk a profil beállításait (Profile - vagy közvetlenül ezen a linken keresztül). Lehetőségünk van itt a következőkre:

  • alapadatok (név, e-mail cím) megváltoztatására,
  • jelszó megváltoztatására (de kell hozzá mindenképpen a régi jelszó is, így biztonságosabb),
  • kétfaktoros azonosításra vagyis hitelesítésre (TFA - Two-Factor Authentication - bővebben erről itt is olvashatunk),
  • kezelhetjük a munkameneteinket, ha esetleg több helyen (böngészőben, eszközön) vagyunk bejelentkezve, akkor itt ki tudjuk jelentkeztetni a másik munkameneteinket,
  • törölhetjük a felhasználónkat is.

Ezek között vannak kötelezően létező beállítási lehetőségek, de van például olyan is, amit "elvehetünk" a felhasználóinktól: a VSCode-ban navigáljunk a config mappában lévő jetstream.php fájlra és keressük meg az alábbi részt:

/*
|--------------------------------------------------------------------------
| Features
|--------------------------------------------------------------------------
|
| Some of Jetstream's features are optional. You may disable the features
| by removing them from this array. You're free to only remove some of
| these features or you can even remove all of these if you need to.
|
*/

'features' => [
  // Features::termsAndPrivacyPolicy(),
  // Features::profilePhotos(),
  // Features::api(),
  Features::teams(['invitations' => true]),
  Features::accountDeletion(),
],

Látható a "features" tömbben, hogy valami engedélyezve van: csapatok (és még az invitálás is), valamint a felhasználó törlése is. Kipróbálhatjuk ezt, hogy ha az "accountDeletion" sort kikommenteljük (és mentjük a fájlt), akkor tényleg eltűnik-e ez a lehetőség a felhasználói profil beállítások közül... és valóban, nem lesz már ott a lehetőség a törlésre.

Próbáljuk ki azt is, hogy a "profilePhotos"-os sor elől kivesszük a kommentelést és mentés után nézzük meg, hogy hogyan változik a profil szerkesztő oldal:

A profil információ bővült egy profilkép feltöltési lehetőséggel, sőt az alapértelmezetten beállított kép (ami nálam egy "A" betűt tartalmaz, ha "Gludovátz Attila" nevet adtam volna meg, akkor "GA" jelenne meg a képen) felkerült a jobb felső sarokba a felhasználónevem helyére.

A jetstream.php szerkesztésével (komment ki-be) nagyon egyszerűen tudunk beállítási funkcionalitásokat hozzáadni a felhasználói (majd később a csapatos) beállítási lehetőségeinkhez. De nem minden beállítás látszódik ebben a fájlban. A Jetstream-es hitelesítési rendszert "támogatja, segíti" a Fortify, amely a hitelesítéssel kapcsolatos teendőket (regisztrációs/bejelentkezési útvonalak regisztrációja, Controller-ek és action-jeinek automatikus létrehozása stb.) végzi el a háttérben. Ez az, ami a hitelesítési rendszer részleteit engedi paraméterezni a számunkra,  hogy például legyen-e lehetősége a látogatóknak regisztrálni, az e-mail legyen-e a felhasználónév, vagy legyen-e e-mail-es megerősítés regisztrációkor, vagy kétfaktorú azonosítás stb. Mindezeket szintén be tudjuk állítani a config / fortify.php fájl releváns részében:

/*
|--------------------------------------------------------------------------
| Features
|--------------------------------------------------------------------------
|
| Some of the Fortify features are optional. You may disable the features
| by removing them from this array. You're free to only remove some of
| these features or you can even remove all of these if you need to.
|
*/

'features' => [
  Features::registration(),
  Features::resetPasswords(),
  // Features::emailVerification(),
  Features::updateProfileInformation(),
  Features::updatePasswords(),
  Features::twoFactorAuthentication([
    'confirm' => true,
    'confirmPassword' => true,
    // 'window' => 0,
  ]),
],

Látható, hogy ez is nagyon hasonlóan működik, mint a jetstream.php hasonló része. Ha például a "twoFactorAuthentication" sorait (több van!) kommenteljük ki, akkor eltűnik ez a beállítási lehetőség a felhasználói profil beállításai közül.

Egy névbeállítást máris végrehajthatunk az oldalon, én például "Attila"-ról "Gludovátz Attila"-ra írom át a nevemet (idézőjelek nélkül) és rákattintok a Save gombra. Ez a szekció egy Livewire komponens: ekkor egy AJAX (aszinkron Javascript és XML felhasználásával) kérés fut le a háttérben, ami az egyszerű felhasználónak csak annyit jelent, hogy nem kellett az egész oldalt újratölteni a gombnyomás hatására, hanem gyorsan és egyszerűen csak az adott szekció frissül és az alapértelmezett profilképem is rögtön megváltozott "A"-ról "GA"-ra.

Kétfaktoros hitelesítés

Ezzel egy biztonságosabb hitelesítési módot tudunk biztosítani az alkalmazásunkhoz. Menjünk rá a profilunk beállításaira az oldalon és a "Two Factor Authentication" résznél engedélyezzük ezt a funkcionalitást. Kérni fogja hozzá az aktuális jelszavunkat, majd egy megerősítést, hogy tényleg akarjuk ezt használni. Ezután megjelenik egy nagy QR kód az oldalon.

A Jetstream alapból a Google Authenticator-t támogatja, érdemes ezt használni, letölteni a telefonunkra és nyissuk is meg. Utána következhet a webalkalmazásban látható QR kód beolvasása az Authenticator (vagy magyarul Hitelesítő) alkalmazásban. Kód felismerés után a kapott 6 számjegyet írjuk be a weboldalon a szövegmezőbe és utána legenerálja nekünk a webalkalmazás a helyreállító kódokat, amelyeket akkor használjunk, ha helyre akarjuk állítani a felhasználónkat, mert elveszítettük a jelszavunkat, érdemes ezeket biztonságos helyre kimenteni. Ezeket majd újra is lehet generálni, ha azt érezzük, hogy már elfogyóban vannak.

Próbáljuk ki a kétfaktoros hitelesítést az oldalon. Ehhez először jelentkezzünk ki. A bejelentkező oldalon a helyes felhasználónév (e-mail) és jelszó megadása után a "Log in"-re kattintva a következő képet kapjuk:

Ide kell beírni azt a 6 számjegyű kódot, amit éppen a Google Authenticator alkalmazás mutat nekünk a telefonunkon a mi webalkalmazásunkhoz kapcsolódóan. Ha helyesen írtuk be és a "Log in"-re kattintunk, akkor ismét be fog már engedni minket az alkalmazásunkba a rendszer. Ha valami mégsem működne, akkor itt tudjuk felhasználni azokat a helyreállítási kódokat (az egyiket közülük, amit még nem használtunk el), amit az előbb kimentettünk egy külön fájlba. Ehhez kattintsunk a "Use a recovery code" linkre és oda másoljuk be az egyik ilyen kódunkat ahhoz, hogy újra beengedjen minket a webalkalmazásunk.

A kipróbálás után, ha úgy érezzük, hogy nincs most szükségünk az ismerkedés során a kétfaktoros hitelesítésre, akkor le is tilthatjuk ezt a szekcióban a "Disable" gomb megnyomásával.

Munkafolyamatok kezelése

Előfordulhat, hogy valahol bejelentkeztünk a webalkalmazásunkba és ottfelejtettük megnyitva a böngészőt. Ez nyilván problémákat okozhat, de segít nekünk a profil oldal "Browser Sessions" szekciója, amely megmutatja, hogy milyen rendszeren, milyen böngészővel és milyen IP címről vagyunk bejelentkezve még az alkalmazásba az aktuálison kívül. Próbáljuk is ezt ki!

Én alapból Firefox-ot használok, de most Chrome-ban is bejelentkezek ugyanazzal a felhasználóval. A Firefox-ban egy frissítés után már látom is az új Chrome-os munkamenetet.

Most pedig, ha azt szeretnénk, hogy ne lehessen a másik böngészőben (vagy helyen) problémás helyzeteket előidézni, akkor kattintsunk a "Log out other browser sessions" gombra, ami után egy jelszavas megerősítést kér tőlünk a rendszer és utána már ki is jelentkeztette a "Chrome-os felhasználót": ha ráfrissítünk a Chrome-ban a dashboard oldalra, akkor már újra a bejelentkező űrlap fog látszódni ott. Ezzel a funkcióval tehát a feledékenységünket tudjuk kijavítani, ami sokszor hasznos tud lenni.

Laravel webalkalmazás, mint API

Bár még nem írtam erről, de a Laravel webalkalmazásunk tökéletesen alkalmas háttérszolgáltatásnak is, amikor egy API-n (Application Programming Interface, magyarul talán az alkalmazás programozási felülete) keresztül egy másik alkalmazás meg tudja szólítani a miénket és akár például adatokat nyerjen így ki belőle, akár valamilyen kalkulációs szolgáltatást vegyen igénybe tőle, ezek itt mind működhetnek. A Jetstream ebben is segít minket, mert nem csak a felhasználókat tudja hitelesíteni, hanem azokat a programokat is, amelyek szolgáltatásokat vennének igénybe a webalkalmazásunktól.

Ezt nem a felhasználói profil oldalán tudjuk engedélyeztetni, hanem a config mappa jetstream.php fájljában, ha kivesszük a kommentet a megfelelő sor elől és elmentjük:

Features::api(),

Akkor utána majd (egy frissítés után) a felhasználói menünkben meg kell jelennie egy új menüpontnak: "API Tokens". Itt tudunk nevet adni annak a külső alkalmazásnak, aminek valamilyen engedélyt akarunk adni arról, hogy mit és mire (létrehoz, kiolvas, szerkeszt és frissít esetleg töröl) használhat az alkalmazásunk által.

Ez azért most még egy kicsit bonyolultabb témakör, de jelen helyzetben elég annyit tudnunk, hogy a Laravel képes háttérszolgáltatóként (backend) működni, ezért is szeretik sokan robosztusabb kliens oldali keretrendszer (React, Vue.js) mögött használni. Ekkor a két terület (backend és frontend) külön-külön fejleszthető, a szükséges információkat pedig a közös felületen (API-n) keresztül tudják átadni egymásnak. A Jetstream itt a kommunikáció szereplőinek a hitelesítésében segíthet: konkrétan a kliens oldalnak kell azonosítania magát az API token segítségével, ha valamit igénybe szeretne venni a backend-től.

A témáról lesz még szó a későbbi bejegyzésekben.

Jelszó emlékeztető küldése

Egy alapvető elvárás a hitelesítési rendszerekkel kapcsolatban, hogy ha a felhasználó elfelejtette a jelszavát, akkor tudja helyreállítani azt. A bejelentkezési űrlapon ez a "Forgot your password?" linket követve érhető el. Ott aztán megadhatjuk az e-mail címünket, amire kimenne az e-mail a hivatkozási linkkel, amire kattintva helyreállíthatnánk a jelszavunkat.Viszont azért fogalmaztam feltételes módban, mivel az alkalmazásunk alapértelmezetten nem képes még e-mail-eket küldeni, ehhez egy SMTP (Simple Mail Transfer Protocol) szolgáltatót kellene beállítani neki az .env fájlban. Ha viszont még nincs ilyenünk, akkor egy kis trükközéssel is megoldhatjuk a jelszó emlékeztetést: nyissuk meg az .env fájlunkat szerkesztésre és módosítsuk a MAIL_MAILER beállítást smtp-ről log-ra, majd mentsük el. Most már a weboldalunkon beírhatjuk az e-mail címünket és kattinthatunk a jelszó emlékeztető kiküldésére.

Ekkor már nem e-mailt fog küldeni az alkalmazásunk, hanem a napló fájljába helyezi el ezt a "kiküldendő levelet". Nyissuk meg a storage / logs / laravel.log fájlt és menjünk a fájl legvégére. Ott kell lennie annak a levélnek, amelyet a rendszer kiküldene amúgy, benne pedig ott van a jelszó helyreállító hivatkozás (link). Másoljuk ezt ki. Megjegyzés: korábban a VSCode ezt a HTML levélformát tökéletesen jelenítette meg, most viszont nálam már elcsúsznak a szövegek és a linkben is vannak nem kívánatos részek. Itt látható egy részlet belőle:

A link tehát ott van, én azt kimásolom elejétől a végéig:

http://localhost/reset-password/b758d4851998945bf1d8bcaa4c7a1bf6ef=
2f15dbd5cc5393d1c768b496f91f8c?email=3Dattila%40gludovatz.hu

Ez így viszont biztosan nem jó, ha csak kimásolom és beillesztem a böngészőmbe. Az első sor végi "=" jel biztosan nem kell, és a 2. sorban az email= utáni "3D" sem fog kelleni. Ezután ha egy sorba hozom a kettőt így, akkor ez már működni fog:

http://localhost/reset-password/b758d4851998945bf1d8bcaa4c7a1bf6ef2f15dbd5cc5393d1c768b496f91f8c?email=attila%40gludovatz.hu

Meg is jelenik a böngészőmben a jelszó helyreállító űrlap:

Ha valakinek alapból jól jelent meg a link, akkor nincs szükség az iménti "trükközésekre". Az új jelszó megadása és megerősítése után tudjuk frissíteni a jelszavunkat, működni fog.

Ennyi felhasználói funkció és beállítás ismertetése után térjünk rá a csapatos funkciókra és beállításokra.


Csapatos funkciók, beállítások

A "csapatos", vagy szerintem sokkal jobb szó erre a "csoportos" beállításokat szintén az oldalon jobb felül érhetjük el: egy lenyíló listából tudjuk a csapatok beállításait szerkeszteni, akár új csapatot is létre tudok hozni vagy az aktuális, saját csapatomat tudom megtekinteni:

A csapat beállításainál képesek vagyunk átírni a csapatunk nevét és tudunk új felhasználókat (e-mail cím alapján) meghívni a csapatba. Az új tag meghívásánál be tudjuk még állítani, hogy milyen szerepkörrel rendelkezzen az új csapattag: alapértelmezetten adminisztrátor van és szerkesztő. Az admin tud mindent, amit most eddig mi is csináltunk, a szerkesztőnek egy kicsit kevesebb joga van, ők főleg a weboldal tartalmait tudják majd szerkeszteni. Ez a két szerepkör kiindulásnak elég, de nyilván a jövőben majd többet is hozzá tudunk adni.

Ha most meg szeretnék hívni valakit a csapatomba, akkor a rendszer kéri az e-mail címet és az új tag szerepkörét és miután helyesen megadtam ezeket, küldene egy e-mail-t a leendő tagnak, hogy jöjjön és regisztráljon be. Viszont a mi alkalmazásunkban még nincsen beállítva az e-mail küldő smtp szolgáltatás. Ezért fontos, hogy előtte be kell regisztrálni egy új felhasználót az oldalra, mondjuk egy másik böngészőben vagy egy inkognitó ablakban. Az új felhasználó e-mail címe legyen ez: jakab@gipsz.hu

Ha ezek után az oldalon meg akarom hívni az új tagot még Attila-ként szerkesztve az oldalt a csapatomba, hívjuk meg: jakab@gipsz.hu e-mail címmel, beállítok neki egy szerepkört, például adminisztrátort, majd az "Add" gombra kattintok, akkor e-mailt szeretne küldeni a webalkalmazás az említett e-mail címre, de az e-mail küldést még nem állítottuk be, így az nem fog működni, viszont... ha átmegyek a másik böngésző ablakba, akkor meg fog jelenni Gipsz Jakab felhasználónál, hogy érkezett hozzá egy meghívó Attila csapatába (esetleg frissíteni kell hozzá a böngészőt a Dashboard oldalon).

A felső sávban lévő jelzést csak bezárni tudom, de utána már a "Gipsz's Team" lenyitásakor látható lesz "Attila's Team" is, vagyis az a csapat, ahova az előbb invitáltam őt.

Ha "Gipsz Jakab"-ként kiválasztjuk Attila csapatát, megváltozik az aktuális csapata, és ha ezek után kéri le a "Team Settings" menüpontot, akkor a következőt kell látnia:

Láthatja, hogy a Csapat tulajdonosa Gludovátz Attila, a csapat nevét (neki nincs joga módosítani rajta), és mivel adminisztrátor, ezért láthatja a csapattagokat is, bár egyelőre csak ő van benne rajtam, az alapítón kívül.


Összegzés

Ebben a bejegyzésben elkezdtünk ismerkedni a Jetstream-mel, amely a Breeze-hez képest már egy komplexebb, több funkcionalitással és beállítással rendelkező felhasználói hitelesítési kiegészítés a Laravel-hez.

Számos funkcionalitását bemutattam, főleg a felhasználókkal kapcsolatban (alapszintű beállítások és módosítások, kétfaktoros hitelesítés, munkamenet bezárás, API alapok, jelszó emlékeztető), de a csapatos beállítási funkciókra is kitértem.

A webalkalmazást továbbra is a Docker és a Laravel Sail segítségével, konténerizáltan futtatom. A bejegyzésben végrehajtott kódváltozások ebben a Github commit-ben érhetők el.