[[oktatas:web:back-end_framework:laravel|< Laravel]] ====== Laravel REST API Drink példa ====== * **Szerző:** Rékási József * Copyright (c) 2024, Rékási József * Licenc: [[https://creativecommons.org/licenses/by-sa/4.0/|CC Attribution-Share Alike 4.0 International]] * Web: https://szit.hu =====Szükséges szoftverek===== ===Windowson=== *PHP *XAMP *Composer *Visual Studio Code vagy más szerkesztő program *Insomnia vagy Postman ===Linuxon=== *PHP *Composer *Mariadb szerver *Visual Studio Code vagy más szerkesztő program *Insomnia vagy Postman ===Linuxon szükséges csomagok=== apt install php phpunit php-bcmath php-mbstring php-xml curl php-curl php-mysql Ez a példaprojekt egy RestApi alkalmazást mutat be amely egy italraktár adatbázis nyilvántartását kezeli. A projekt Laravel 10 verzióval készült. =====Adatbázis===== **__drinks__** ( id, drink, amount, type_id, package_id ) **__types__** ( id, type ) **__packages__** ( id, package ) =====Projekt létrehozás===== composer create-project laravel/laravel Drink =====Migrációs állományok===== Az adatbázisnak üresen léteznie kell, az adattáblákat a megfelelő mezőkkel a migrációs állományok fogják létrehozni. ====drinks==== php artisan make:migration create_drinks_table A drinks táblában tároljuk az italokat. public function up(): void { Schema::create('drinks', function (Blueprint $table) { $table->id(); $table->string( "drink" ); $table->integer( "amount" ); $table->foreignId( "type_id" ); $table->foreignId( "packages_id" ); $table->timestamps(); }); } ====types==== php artisan make:migration create_types_table A types táblában tároljuk az italok típusait ( Bor, Sör, üdítő, ...stb ) public function up(): void { Schema::create('types', function (Blueprint $table) { $table->id(); $table->string( "type" ); }); } ====packages==== php artisan make:migration create_packages_table A packages táblában tároljuk az italok kiszereléseit ( Üveges, Hordós, ...stb ) public function up(): void { Schema::create('packages', function (Blueprint $table) { $table->id(); $table->string( "package" ); }); } Adattáblák létrehozása: php artisan migrate =====Modellek===== Az adattáblákhoz tartozó modellek fogják kezelni az adatmozgást az alkalmazás és az adatbázis között. Fel kell venni az írható mezők listáját és szükség szerint ignorálni kell a timestamps mezőt. A model nevének meg kell egyeznie az adattábla nevével de egyes számban. ====Drink==== php artisan make:model Drink class Drink extends Model { use HasFactory; protected $fillable = [ "drink", "amount", "type_id", "package_id" ]; public function type() { return $this->belongsTo( Type::class ); } public function package() { return $this->belongsTo( Package::class ); } } ====Type==== php artisan make:model Type class Type extends Model { use HasFactory; protected $fillable = [ "type" ]; public $timestamps = false; public function drink() { return $this->hasMany( Drink::class ); } } ====Package==== php artisan make:model Package class Package extends Model { use HasFactory; protected $fillable = [ "package" ]; public $timestamps = false; public function drink() { return $this-hasMany( Drink::class ); } } =====Resources osztályok===== A resources osztályok állítják össze a válaszban küldött adathalmazt. Ezeket az adatokat mi adjuk meg, mit szeretnénk látni a kimeneten. A resources osztályok neve megegyezik a model nevével. php artisan make:resource Drink Töltsük fela toArray() metódus tömbjét az adathalmazzal. ====DrinkResource==== public function toArray(Request $request): array { return [ "id" => $this->id, "drink" => $this->drink, "amount" => $this->amount, "type" => $this->type->type, "package" => $this->package->package ]; } ====TypeResource==== php artisan make:resource Type public function toArray(Request $request): array { return [ "type" => $this->type ]; } ====PackageResource==== php artisan make:resource Package public function toArray(Request $request): array { return [ "package" => $this->package ]; } =====Kontrollerek===== A kontrollerek metódusaiban történik a vezérlés, a végpontok ezekre a metódusokra mutatnak. A vezérlő osztályoknak érdemes külön könyvtárat létrehozni. Ezt könyvtárat a php artisan automatikusan létrehozza, ha nem létezik. A válaszok küldését mivel majdnem minden művelet visszatér valamilyen eredménnyel érdemes külön osztályba szervezni a kódismétlés kiküszöbölése végett. ====ResponseController==== php artisan make:controller Api/ResponseController Két metódust tartalmaz, a sikeres és a hibás művletek eredményét adja vissza. ===Sikeres művelet=== public function sendResponse( $data, $message ) { $response = [ "sucess" => true, "data" => $data, "message" => $message ]; return response()->json( $response, 200 ); } ===Hibás művelet=== public function sendError( $error, $errorMessages = [], $code = 404 ) { $response = [ "success" => false, "message" => $error ]; if( !empty( $errorMessages )) { $response[ "data" ] = $errorMessages; } return response()->json( $response, $code ); } ====DrinkController==== php artisan make:controller Api/DrinkController A DrinkControllert származtassuk a ResponseControllertől. A ResponseControllert és a modelt fel kell venni útvonalra. Kérjük le a drinks tábla adatait. use App\Http\Controllers\Api\ResponseController; use App\Models\Drink; class DrinkController extends ResponseController { public function getDrinks() { $drinks = Drink::all(); return $this->sendResponse( $drinks, "Adatok betöltve" ); } } Teszteljük Insomnia vagy Postman programban. Ez a metódus minden adatot visszaad a táblából, de az idegen tábláknak csak az id idegen kulcsai látszanak. Kapcsoljuk hozzá a két másik táblát és nézzük meg az eredményt. public function getDrinks() { $drinks = Drink::with( "type", "package" )->get(); return $this->sendResponse( $drinks, "Adatok betöltve" ); } ===Egy ital lekérése=== Most használjuk a létrehozott resources osztályt az adatok megjelenítésére. Az osztályt be kell emelni a kontrollerbe. Mivel a model és a resorces osztály neve megegyezik ezért el kell látnunk aliasszal, hogy a hivatkozás egyértelmű legyen. use App\Http\Resorces\Drink as DrinkResource; public function getOneDrink( $id ){ $drink = Drink::with( "type", "package" )->find( $id ); if( is_null( $drink )){ return $this->sendError( "Nincs ilyen ital" ); } return $this->sendResponse( new DrinkResource( $drink ), "Ital kiválasztva" ); } ===Ital hozzáadása=== Itt szükség van a kapott ital típusának és a kiszerelésének az azonosítójára. Ezeket egy másik adattáblából kell lekérni, ezt az adott adattábla saját kontrollere fogja szolgáltatni. A beérkező adatokat validálni kell. A validálást a saját request osztály végzi. Ezt fel kell venni útvonalra. use App\Http\Requests\DrinkAddChecker; public function addDrink( DrinkAddChecker $request ) { $request->validated(); $input = $request->all(); $drink = new Drink; $drink->drink = $input["drink"]; $drink->amount = $input["amount"]; $drink->type_id = ( new TypeController )->getTypeId( $input[ "type" ]);; $drink->package_id = ( new PackageController )->getPackageId( $input[ "package" ]); $drink->save(); return $this->sendResponse( new DrinkResource( $drink ), "Ital kiírva" );; } ===Italok frissítése=== Az adatokat itt is validálni kell, a szükséges azonosítokat az adattábla saját kontrollere szolgáltatja. public function updateDrink( DrinkAddChecker $request, $id ) { $request->validated(); $input = $request->all(); $drink = Drink::find( $id ); $drink->drink = $input[ "drink" ]; $drink->amount = $input[ "amount" ]; $drink->type_id = ( new TypeController )->getTypeId( $input[ "type" ]); $drink->package_id = ( new PackageController )->getPackageId( $input[ "package" ]); $drink->update(); return $this->sendResponse( new DrinkResource( $drink ), "Ital frissítve" ); } ===Ital törlése=== public function deleteDrink( $id ) { $drink = Drink::find( $id ); $drink->delete(); return $this->sendResponse( new DrinkResource( $drink ), "Ital törölve" ); } ====TypeController==== Ez a vezérlő felelős a types tábla adatkezeléséért a megfelelő metódusokon keresztül. Az osztály szintén a ResponseControllertől öröklődik és be kell emelni a szükséges más osztályokat is. use App\Models\Type; use App\Http\Controllers\api\ResponseController as ResponseController; use App\Http\Resources\Type as TypeResource; use App\Http\Requests\TypeAddChecker; ===Típusok lekérése=== public function getTypes() { $types = Type::all(); return $this->sendResponse( $types, "Típusok betöltve" ); } ===Új típus felvétele=== Az adatot itt is validálni kell, ezt a saját validáló osztály végzi. public function addType( TypeAddChecker $request ) { $request->validated(); $input = $request->all(); $type = Type::create( $input ); return $this->sendResponse( new TypeResource( $type ), "Sikeres kiírás" ); } ===Típus frissítése=== public function updateType( TypeAddChecker $request, $id ) { $request->validated(); $input = $request->all(); $type = Type::find( $id ); $type->type = $input[ "type" ]; $type->update(); return $this->sendResponse( new TypeResource( $type ), "Típus frissítve" ); } ===Típus törlése=== public function deleteType( $id ) { $type = Type::find( $id ); if( is_null( $type )) { return $this->sendError( "Nincs ilyen típus" ); }else { $type->delete(); return $this->sendResponse( new TypeResource( $type ), "Típus törölve" ); } } ===Típus azonosító lekérése=== public function getTypeId( $typeName ) { $type = Type::where( "type", $typeName )->first(); $id = $type->id; return $id; } ====PackageController==== Ez a vezérlő felelős a kiszerelések adatkezeléséért. Örökölni kell a ResponseControllert és ide is be kell emelni a szükséges osztályokat. use App\Models\Package; use App\Http\Controllers\api\ResponseController as ResponseController; use App\Http\Resources\Package as PackageResource; use App\Http\Requests\PackageAddChecker; ===Kiszerelések lekérése=== public function getPackages() { $packages = Package::all(); return $this->sendResponse( $packages, "Kiszerelések betöltve" ); } ===Új kiszerelés felvétele=== public function addPackage( PackageAddChecker $request ) { $request->validated(); $input = $request->all(); $package = Package::create( $input ); return $this->sendResponse( new PackageResource( $package ), "Sikeres kiírás" ); } ===Kiszerelés frissítése=== public function updatePackage( PackageAddChecker $request, $id ) { $request->validated(); $input = $request->all(); $package = Package::find( $id ); $package->package = $input[ "package" ]; $package->update(); return $this->sendResponse( new PackageResource( $package ), "Kiszerelés frissítve" ); } ===Kiszerelés törlése==== public function deletePackage( $id ) { $package = Package::find( $id ); if( is_null( $quantity )) { return $this->sendError( "Nincs ilyen kiszerelés" ); }else { $package->delete(); return $this->sendResponse( new PackageResource( $package ), "Kiszerelés törölve" ); } } ===Kiszerelés azonosító lekérése=== public function getPackageId( $packageName ) { $package = Package::where( "package", $packageName )->first(); $id = $package->id; return $id; } =====Request osztályok===== Ezek az osztályok felelősek a beérkező adat ellenőrzéséért. A rules() metódus ellenőrzi az adatokat, a messages() metódus a saját hibaüzenetet generálja és a failedValidation() metódus a hibaüzenetet küldi. Be kell emelni két külső osztályt. use Illuminate\Http\Exceptions\HttpResponseException; use Illuminate\Contracts\Validation\Validator; ====DrinkAddChecker==== php artisan make:request DrinkAddChecker public function rules(): array { return [ "drink" => "required", "amount" => "required", "type" => "required", "package" => "required" ]; } public function messages() { return [ "drink.required" => "Név elvárt", "amount.required" => "Mennyiség elvárt", "type.required" => "Típus elvárt", "packages.required" => "Kiszerelés elvárt", ]; } public function failedValidation( Validator $validator ) { throw new HttpResponseException( response()->json([ "success" => false, "message" => "Adatbeviteli hiba", "data" => $validator->errors() ])); } ====TypeAddChecker==== php artisan make:request TypeAddChecker public function rules(): array { return [ "type" => "required" ]; } public function messages() { return [ "type.required" => "Név elvárt" ]; } public function failedValidation( Validator $validator ) { throw new HttpResponseException( response()->json([ "success" => false, "message" => "Adatbeviteli hiba", "data" => $validator->errors() ])); } ====PackageAddChecker==== php artisan make:request PackageAddChecker public function rules(): array { return [ "package" => "required" ]; } public function messages() { return [ "package.required" => "Kiszerelés elvárt" ]; } public function failedValidation( Validator $validator ) { throw new HttpResponseException( response()->json([ "success" => false, "message" => "Adatbeviteli hiba", "data" => $validator->errors() ])); } ====UserRegisterChecker==== php artisan make:request UserRegisterChecker Ez az osztály végzi a bevitt adatok ellenőrzését a megfelelő szabályokon keresztül. A rules() metódus a szabályokat tartalmazza, a messages() metódus a saját hibaüzeneteket és a failedValidation() metódus küldi a hibaüzeneteket. Emeljük be a szükséges osztályokat use Illuminate\Http\Exceptions\HttpResponseException; use Illuminate\Contracts\Validation\Validator; public function rules(): array { return [ "name" => "required", "email" => "required", "password" => "required", "confirm_password" => "required|same:password" ]; } public function messages() { return [ "name.required" => "Név kötelező", "email.required" => "Email kötelező", "password.required" => "Jelszó kötelező", "confirm_password.same" => "Nem egyező jelszó" ]; } public function failedValidation( Validator $validator ) { throw new HttpResponseException( response()->json([ "success" => false, "message" => "Adatbeviteli hiba", "data" => $validator->errors() ])); } ====UserLoginChecker==== php artisan make:request UserLoginChecker Ez az osztály végzi a bejelentkezés adatainak az ellenőrzését, ide is be kell emelni a szükséges osztályokat. use Illuminate\Http\Exceptions\HttpResponseException; use Illuminate\Contracts\Validation\Validator; public function rules(): array { return [ "name" => "required", "password" => "required" ]; } public function messages() { return [ "name.required" => "Név kötelező", "password.required" => "Jelszó kötelező" ]; } public function failedValidation( Validator $validator ) { throw new HttpResponseException( response()->json([ "success" => false, "message" => "Adatbeviteli hiba", "data" => $validator->errors() ])); } =====Útvonalak===== Az útvonalakat az App\routes\api.php állományban rögzítsük. Az állományban fel kell venni útvonalra a kontrollereket. use App\Http\Controllers\DrinkController; use App\Http\Controllers\api\TypeController; use App\Http\Controllers\api\QuantityController; use App\Http\Controllers\api\AuthController; ====Italok==== //Italok lekérése Route::get( "/drinks", [ DrinkController::class, "getDrinks" ]); //Egy ital lekérése Route::get( "/oneDrink/{id}", [ DrinkController::class, "getOneDrink" ]); //Új ital felvétele Route::post( "/addDrink", [ DrinkController::class, "addDrink" ]); //Ital frissítése Route::put( "/updatedrink/{id}", [ DrinkController::class, "updateDrink" ]); //Ital törlése== Route::delete( "/deleteDrink/{id}", [ DrinkController::class, "deleteDrink" ]); ====Típusok==== //Típusok lekérése Route::get( "/types", [ TypeController::class, "getTypes" ]); //Új típus felvétele Route::post( "/addtype", [ TypeController::class, "addType" ]); //Típus frissítése Route::put( "/updatetype/{id}", [ TypeController::class, "updateType" ]); //Típus törlése Route::delete( "/deletetype/{id}", [ TypeController::class, "deleteType" ]); ====Kiszerelések==== //Kiszerelések lekérése Route::get( "/packages", [ PackageController::class, "getPackages" ]); //Új kiszerelés felvétele Route::post( "/addpackage", [ PackageController::class, "addPackage" ]); //Kiszerelés frissítése Route::put( "/updatepackage/{id}", [ PackageController::class, "updatePackage" ]); //Kiszerelés törlése Route::delete( "/deletepackage/{id}", [ PackageController::class, "deletePackage" ]); =====Azonosítás===== A felhasználók kezeléséhez szükség van sanctum csomagra composer require laravel/sanctum A sanctum kiszolgáló beállítása: php artisan vendor:publish --provider="Laravel\Sanctum\SanctumServiceProvider" A Kernel.php állományban engedélyezni kell a csoportos middleware api szekciójában a Sanctum használatát. Vegyük ki a kommentet a megfelelő sor elől. protected $middlewareGroups = [ 'web' => [ \App\Http\Middleware\EncryptCookies::class, \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class, \Illuminate\Session\Middleware\StartSession::class, \Illuminate\View\Middleware\ShareErrorsFromSession::class, \App\Http\Middleware\VerifyCsrfToken::class, \Illuminate\Routing\Middleware\SubstituteBindings::class, ], 'api'=> //\Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class, \Illuminate\Routing\Middleware\ThrottleRequests::class.':api', \Illuminate\Routing\Middleware\SubstituteBindings::class, ], ]; A felhasználók kezelése szintén adatbázisból történik, az ehhez szükséges adat táblák, a users és a personal_access_tokens a migráció során automatikusan létrejönnek. Szintén automatikusan létrejön a User model is, ebben a szükséges három mező: name, email, password. Ha User modelben nem találjuk, emeljük be a HasApiTokens osztályt. use Laravel\Sanctum\HasApiTokens A users táblát ki kell egészíteni két új mezővel amelyben a bejelentkezések számát és az esetleges kitiltás lejárati idejét tároljuk. php artisan make:migration add_banned_data_to_users_table public function up(): void { Schema::table('users', function (Blueprint $table) { $table->timestamp( "login_attempts" )->default( 0 ); $table->timestamp( "banned_time" )->nullable()->default( null ); }); } ====UserController==== Ez a vezérlő felelős a felhasználók regisztrációjáért, a bejelentkezésekért és a kijelentkezésekért. Négy metódusa van a register(), a logIn(), a logOut() és az isValidUser(). A kontrollert örököltessük a ResponseControllertől és emeljük be, illetve a még szükséges osztályokat is. use App\Http\Controllers\Api\ResponseController as ResponseController; use Illuminate\Support\Facades\Auth; use App\Models\User; use App\Http\Requests\UserRegisterChecker; use App\Http\Requests\UserLoginChecker; use Carbon\Carbon; Az adatokat itt is validálni kell, ezt a saját ellenőrző osztály végzi. public function register( UserRegisterChecker $request ) { $request->validated(); $input = $request->all(); $input[ "password" ] = bcrypt( $input[ "password" ]); $user = User::create( $input ); $success[ "name" ] = $user->name; return $this->sendResponse( $success, "Sikeres regisztrácio" ); } Ellenőrizni kell, hogy a bejelentkezni próbáló felhasználó létezik-e. Ha létezik meghívja a login() metódust, ha nem létezik hibaüzenetet ad. public function isValidUser( UserLoginChecker $request ) { $count = User::where( "name", $request->name )->count(); if( $count != 0 ) { $data = $this->login( $request ); return $data; }else { return $this->sendError( "Azonosítási hiba", [ "Nincs ilyen felhasználó" ] ); } } Most következik a felhasználó ellenőrzése, a felhasználónév jelszó páros. Ha a felhasználó háromszor hibásan adja meg a jelszavát, egy percre tíltásba kerül és hibaüzenetet kap. A felhasználó nevét és a tiltás idejének lejáratát emailben elküldjük egy adott címre. Sikeres bejelentkezés esetén generálni kell egy tokent ami a personal_access_tokens táblában tárolódik és nullázni kell a hibás bejelentkezés számlálókat. A hibás próbálkozások számlálását és rögzítését a BanningTimeController végzi. public function login( UserLoginChecker $request ) { $bannedTime = null; $request->validated(); if(( Auth::attempt([ "name" => $request->name, "password" => $request->password ]))) { $bannedTime = ( new BanningTimeController )->getUserBannedTime( $request->name ); if( $bannedTime > Carbon::now( "Europe/Budapest" ) ) { return $this->sendError( "Túl sok próbálkozás", [ "nextlogin" => $bannedTime ], 429 ); } ( new BanningTimeController )->resetBannedData( $request->name ); $authUser = Auth::user(); $success[ "token" ] = $authUser->createToken( $authUser->name."Token" )->plainTextToken; $success[ "name" ] = $authUser->name; return $this->sendResponse( $success, "Sikeres bejelentkezés" ); }else { $loginCounter = ( new BanningTimeController )->getLoginAttempts( $request->name ); if( $loginCounter < 3 ) { ( new BanningTimeController )->setLoginAttempts( $request->name ); return $this->sendError( "Sikertelen azonosítás", [ "error" => "Hibás felhasználónév vagy jelszó" ]); }else if( $loginCounter == 3 && is_null( $bannedTime )) { $bannedTime = ( new BanningTimeController )->setUserBannedTime( $request->name ); $allert = ( new AllertController )->sendEmail( $request->name, $bannedTime ); return $this->sendError( "Sikertelen azonosítás", [ "error" => "Túl sok próbálkozás" ]); } } } Kijelentkezéskor a tokent törölni kell. public function logOut( Request $request ){ auth("sanctum")->user()->currentAccessToken()->delete(); return response()->json("Sikeres kijelentkezés"); } ====BanningTimeController==== Ennek a vezérlőnek a feladata kezelni a hibás bejelentkezések rögzítését és a kitiltás időintervallumának a beállítását. Emeljük be a szükséges osztályokat. use Carbon\Carbon; use App\Models\User; class BanningTimeController extends Controller { public function getUserBannedTime( $name ) { $user = User::where( "name", $name )->first(); return $user->banned_time; } public function getLoginAttempts( $name ) { $user = User::where( "name", $name )->first(); $loginAttempts = $user->login_attempts; return $loginAttempts; } public function setLoginAttempts( $name ) { User::where( "name", $name )->increment( "login_attempts" ); } public function setUserBannedTime( $name ) { $user = User::where( "name", $name )->first(); $banned_time = Carbon::now( "Europe/Budapest" )->addSeconds( 60 ); $user->banned_time = $banned_time; $user->save(); return $banned_time; } public function resetBannedData( $name ) { $user = User::where( "name", $name )->first(); $user->login_attempts = 0; $user->banned_time = null; $user->save(); } } =====Email küldése===== Két osztályra és egy nézetre van szükség, ezeket generáljuk le. php artisan make:controller Api\AllertController php artisan make:mail AllertMail A resources\views könyvtárban hozzuk létre a mail.blade.php állományt. Az .env állományban állítsuk be az email küldéséhez szükséges adatokat. A példában gmail fiókot használunk. MAIL_MAILER=smtp MAIL_HOST=smtp.gmail.com MAIL_PORT=587 MAIL_USERNAME=a_sajat_fiokod@gmail.com MAIL_PASSWORD=a_titkos_jelszo MAIL_ENCRYPTION=tls MAIL_FROM_ADDRESS="drink@laravel.com" //Ez az emailcím fog megjelenni a levélben. MAIL_FROM_NAME="Drink projekt" // Ez a név fog megjelenni a levében. ====AllertController==== Ennek a vezérlőnek a feladata összeállítani az email tartalmát és itt adhatjuk meg a címzettet. Emeljük be a szükséges osztályokat. use App\Mail\AllertMail; use Illuminate\Support\Facades\Mail; class AllertController extends Controller { public function sendEmail( $user, $time ) { $content = [ "title" => "Felhasználó blokkolva", "user" => $user, "time" => $time ]; Mail::to( "a_sajat_email_cimed@gmail.com" )->send( new AllertMail( $content )); return false; } } ====AllertMail==== A konstruktorban vegyük át az összeállított adatokat. Az envelop() metódusban adhatjuk meg az email tárgyát. A content() metódusban hivatkozunk a nézetre amiben a levél kinézete van. Az attachments() metódusban van lehetőség állomány csatolására. class AllertMail extends Mailable { use Queueable, SerializesModels; public $content; public function __construct( $content ) { $this->content = $content; } public function envelope(): Envelope { return new Envelope( subject: 'Allert Mail', ); } public function content(): Content { return new Content( view: 'mail', ); } public function attachments(): array { return []; } } ====Mail nézet==== Ebben a nézetben kerül összeállításra a levél kinézete, ide emeljük be a küldeni kívánt adatokat és írhatunk hozzá további szöveget.

{{ $content[ "title" ] }}


Idő: {{ $content[ "time" ] }}


{{ $content[ "user" ] }}

1 percre kitiltva túl sok sikertlen próbálkozás miatt.

=====Védett útvonalak===== A felhaszálóknak csak bejelentkezés után engedünk végrehajtani bizonyos műveleteket. Az ezekre mutató végpontokat védetté kell tenni, a middleware csomagon keresztül a Sanctum ellenőrzi jogosultságokat. Ezt a generált tokennel igazolhatjuk. A routes/api állományban állítsuk be a védett útvonalakat, vegyük fel a middleware group csoportba. Azokat az útvonalakat amelyeket nem kívánunk védeni, hagyjuk kívül. Route::group([ "middleware" => [ "auth:sanctum" ]], function() { Route::post( "/logout", [ AuthController::class, "logOut" ]); Route::post( "/addDrink", [ DrinkController::class, "addDrink" ]); Route::put( "/updatedrink/{id}", [ DrinkController::class, "updateDrink" ]); Route::delete( "/deletedrink/{id}", [ DrinkController::class, "deleteDrink" ]); Route::post( "/addtype", [ TypeController::class, "addType" ]); Route::put( "/updatetype/{id}", [ TypeController::class, "updateType" ]); Route::delete( "/deletetype/{id}", [ TypeController::class, "deleteType" ]); Route::post( "/addpackage", [ PackageController::class, "addPackage" ]); Route::put( "updatepackage/{id}", [ PackageController::class, "updatePackage" ]); Route::delete( "/deletepackage/{id}", [ PackageController::class, "deletePackage" ]); }); Route::post( "/register", [ AuthController::class, "register" ])->middleware( "throttle:100,43200" );; Route::post( "/login", [ AuthController::class, "isValidUser" ])->middleware( "throttle:100,43200" ); Route::get( "/drinks", [ DrinkController::class, "getDrinks" ]); Route::get( "/oneDrink/{id}", [ DrinkController::class, "getOneDrink" ]); Route::get( "/types", [ TypeController::class, "getTypes" ]); Route::get( "/quantities", [ QuantityController::class, "getQuantities" ]);