Wstęp
W każdej dynamicznej aplikacji webowej, zarządzanie uprawnieniami i rolami użytkowników jest nieodzownym elementem. Laravel, będący jednym z najbardziej rozpowszechnionych frameworków PHP, umożliwia elastyczne podejście do tego zagadnienia. W tym artykule, skupimy się na tworzeniu własnego systemu zarządzania rolami w Laravelu. Przejdziemy przez proces od podstaw – począwszy od instalacji i konfiguracji użytkowników z wykorzystaniem szablonów Blade i Laravel Breeze, aż po tworzenie dedykowanego modelu i tabeli dla ról oraz tabeli pośredniej (pivot). Na koniec, zintegrujemy te elementy z istniejącym kodem Laravela, aby stworzyć kompleksowy i funkcjonalny system zarządzania rolami.
Instalacja i Konfiguracja Użytkowników
Pierwszym krokiem w dodawaniu obsługi ról do Twojej aplikacji Laravel jest skonfigurowanie środowiska użytkowników. Wykorzystamy do tego Laravel Breeze, który jest prostym, lecz potężnym rozwiązaniem do zarządzania uwierzytelnianiem. Oto kroki, które należy wykonać:
Instalacja Laravel Breeze:
composer require laravel/breeze --dev
Instalacja Breeze i generowanie szablonów Blade:
php artisan breeze:install
Migracja bazy danych, aby uwzględnić tabele użytkowników:
php artisan migrate
Instalacja zależności frontendowych i kompilacja assetów:
npm install
npm run dev
Po wykonaniu tych kroków, Twoja aplikacja będzie miała podstawową strukturę uwierzytelniania i rejestracji użytkowników.
Tworzenie Migracji i Modeli dla Ról
Aby w pełni zaimplementować system zarządzania rolami w Laravelu, potrzebujemy stworzyć odpowiednie modele i migracje. Modele będą reprezentować encje w naszej bazie danych, natomiast migracje pozwolą na stworzenie odpowiednich tabel.
Tworzenie Modelu Roli
Za pomocą Artisan, narzędzia linii komend Laravela, tworzymy model Role oraz migrację dla niego:
php artisan make:model Role -m
Parametr -m
automatycznie generuje plik migracji dla modelu.
Tworzenie Migracji dla Tabeli Pośredniej:
Następnie, tworzymy migrację dla tabeli pośredniej role_user
, która będzie przechowywać relacje między użytkownikami a rolami:
php artisan make:migration create_role_user_table --create=role_user
Definiowanie Migracji dla roles
:
Migracja dla tabeli roles
definiuje strukturę tej tabeli. Ważne są tutaj dwa pola: id
jako klucz główny i name
przechowujący nazwę roli.
// create_roles_table.php
Schema::create('roles', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->timestamps();
});
Definiowanie Migracji dla role_user
:
Tabela role_user
jest tabelą pośrednią, która łączy użytkowników i role. Kluczowe tutaj jest użycie foreignId
dla user_id
i role_id
, co tworzy relacje z tabelami użytkowników i ról. Ustawienie onDelete('cascade')
oznacza, że przy usunięciu użytkownika lub roli, powiązane rekordy w tej tabeli zostaną również usunięte.
// create_role_user_table.php
Schema::create('role_user', function (Blueprint $table) {
$table->foreignId('user_id')->constrained()->onDelete('cascade');
$table->foreignId('role_id')->constrained()->onDelete('cascade');
$table->primary(['user_id', 'role_id']);
});
Wykonywanie Migracji:
Po zdefiniowaniu migracji, wykonujemy je, aby stworzyć tabele w bazie danych:
php artisan migrate
Po wykonaniu tych kroków, struktura bazy danych jest przygotowana do obsługi systemu ról. Mamy tabelę roles
do przechowywania różnych ról i tabelę role_user
do zarządzania relacjami między użytkownikami a ich rolami.
Użycie Seederów do Inicjalizacji Danych
Po skonfigurowaniu tabel w bazie danych, kolejnym krokiem jest wypełnienie ich początkowymi danymi. W Laravelu, służą do tego tzw. seedery, które umożliwiają łatwe dodawanie domyślnych danych do bazy. W tym przypadku, skupimy się na wypełnieniu tabeli roles
domyślnymi rolami.
Tworzenie Seedera:
Najpierw tworzymy seeder dla tabeli roles
za pomocą Artisan:
php artisan make:seeder RolesTableSeeder
To polecenie generuje szablon seeder’a w katalogu database/seeders
.
Dodawanie Domyślnych Ról:
W pliku RolesTableSeeder.php
, definiujemy zestaw domyślnych ról, które chcemy dodać do naszej aplikacji. Role w naszym przypadku to 'admin’, 'user’, i 'guest’.
// RolesTableSeeder.php
use Illuminate\Database\Seeder;
use App\Models\Role;
class RolesTableSeeder extends Seeder
{
public function run()
{
$roles = ['admin', 'user', 'guest'];
foreach ($roles as $role) {
Role::create(['name' => $role]);
}
}
}
W funkcji run()
definiujemy tablicę ról, a następnie iterujemy po niej, tworząc nowe obiekty Role
za każdym razem. Metoda create
jest wygodnym sposobem na dodawanie nowych rekordów do bazy danych, łączącym w sobie tworzenie nowej instancji modelu oraz zapis do bazy.
Uruchomienie Seedera:
Po zdefiniowaniu seeder’a, uruchamiamy go, aby wypełnić bazę danych początkowymi danymi:
php artisan db:seed --class=RolesTableSeeder
To polecenie uruchomi tylko seeder RolesTableSeeder
, dzięki czemu możemy być pewni, że tylko tabela roles
zostanie wypełniona.
Seeder RolesTableSeeder
jest kluczowym elementem w procesie inicjalizacji aplikacji. Pozwala na automatyczne stworzenie podstawowej struktury ról, co jest wyjątkowo przydatne, zwłaszcza podczas pierwszego uruchomienia aplikacji na środowisku produkcyjnym lub testowym.
Tworzenie Relacji Między Modelami Użytkowników i Ról
Teraz, gdy mamy stworzoną strukturę tabel i początkowe dane, następnym krokiem jest zdefiniowanie relacji między modelami w Laravelu. Laravel oferuje różne typy relacji, a w tym przypadku skorzystamy z relacji typu „wiele do wielu” (belongsToMany
), aby połączyć modele User
i Role
.
Relacja w Modelu User
:
W modelu User
definiujemy metodę roles()
, która umożliwia dostęp do przypisanych użytkownikowi ról.
// User.php
public function roles()
{
return $this->belongsToMany(Role::class);
}
Metoda belongsToMany
informuje Laravela, że jeden użytkownik może mieć przypisane wiele ról. Laravel automatycznie szuka tabeli pośredniej role_user
(na podstawie konwencji nazewnictwa), aby zarządzać tą relacją.
Relacja w Modelu Role
:
Analogicznie, w modelu Role
definiujemy metodę users()
, która pozwala na dostęp do użytkowników, którzy mają przypisaną daną rolę.
// Role.php
public function users()
{
return $this->belongsToMany(User::class);
}
Ta relacja również jest typu „wiele do wielu”. Dzięki temu możemy łatwo zarządzać przypisaniem ról do użytkowników oraz odwrotnie – sprawdzać, jakich użytkowników obejmuje dana rola.
Te relacje są kluczowe dla funkcjonowania systemu zarządzania rolami. Pozwalają na elastyczne zarządzanie przypisaniem ról, umożliwiając łatwe dodawanie, usuwanie lub modyfikowanie ról przypisanych do użytkowników. Dodatkowo, dzięki wykorzystaniu Eloquent ORM, działania te są intuicyjne i wymagają minimalnej ilości kodu.
Tworzenie Middleware dla Kontroli Dostępu na Podstawie Roli
Middleware w Laravelu to potężne narzędzie do filtrowania żądań HTTP przed dotarciem do aplikacji lub przed przekazaniem odpowiedzi do klienta. W kontekście systemu zarządzania rolami, middleware może być używane do sprawdzania, czy zalogowany użytkownik posiada odpowiednią rolę, aby uzyskać dostęp do określonej części aplikacji.
Tworzenie Middleware:
Najpierw stworzymy nowy middleware, który będzie odpowiedzialny za sprawdzanie ról użytkowników.
php artisan make:middleware CheckRole
To polecenie generuje szablon klasy middleware w katalogu app/Http/Middleware
.
Implementacja Logiki Middleware:
Wewnątrz klasy CheckRole
, dodajemy logikę, która sprawdza, czy zalogowany użytkownik posiada wymaganą rolę.
// CheckRole.php
public function handle($request, Closure $next, $role)
{
if (!Auth::check() || !$request->user()->roles->contains('name', $role)) {
// Użytkownik nie ma wymaganej roli, przekieruj go lub zrób coś innego
abort(403, 'Unauthorized action.');
}
return $next($request);
}
W tym kodzie, najpierw sprawdzamy, czy użytkownik jest zalogowany (Auth::check()
). Następnie, za pomocą metody contains
, sprawdzamy, czy kolekcja ról przypisanych do użytkownika zawiera rolę o nazwie przekazanej jako argument. Jeśli nie, żądanie jest przerywane i zwracany jest błąd 403 (Unauthorized).
Rejestracja Middleware:
Aby zarejestrować nasz middleware CheckRole
w pliku Kernel.php
aplikacji Laravel, należy dodać go do listy $routeMiddleware
. To umożliwi wywołanie middleware w określonych trasach (routes) lub kontrolerach. Oto jak powinien wyglądać zmodyfikowany fragment pliku Kernel.php
:
protected $routeMiddleware = [
// ... (inne zdefiniowane middleware)
'checkRole' => \App\Http\Middleware\CheckRole::class,
];
Middleware CheckRole
jest niezwykle przydatny do ochrony tras (routes) w aplikacji Laravel, gwarantując, że tylko użytkownicy z odpowiednimi rolami będą mieli dostęp do określonych sekcji aplikacji. Jest to kluczowy element w zarządzaniu dostępem i bezpieczeństwem w aplikacjach opartych o role.
Utworzenie Własnej Dyrektywy Blade dla Ról Użytkowników
Dyrektywy Blade w Laravelu umożliwiają dodawanie własnych instrukcji warunkowych bezpośrednio w szablonach widoku. Można je wykorzystać do sprawdzania, czy zalogowany użytkownik posiada określoną rolę, co jest szczególnie przydatne w sytuacjach, gdzie chcemy wyświetlić lub ukryć pewne części widoku w zależności od roli użytkownika.
Rejestracja Dyrektywy Blade:
Aby utworzyć własną dyrektywę Blade, trzeba ją zarejestrować w metodzie boot
klasy AppServiceProvider
. AppServiceProvider
to miejsce, gdzie można definiować globalne zachowania i usługi dla całej aplikacji.
use Illuminate\Support\Facades\Blade;
use Illuminate\Support\Facades\Auth;
public function boot()
{
Blade::if('hasrole', function ($role) {
return Auth::check() && Auth::user()->roles->contains('name', $role);
});
}
W tym kodzie, tworzymy dyrektywę @hasrole
, która sprawdza, czy zalogowany użytkownik posiada rolę o określonej nazwie. Dyrektywa ta wykorzystuje funkcję Auth::check()
do sprawdzenia, czy użytkownik jest zalogowany, a następnie Auth::user()->roles->contains('name', $role)
do sprawdzenia, czy posiada on daną rolę.
Tworzenie własnych dyrektyw Blade to efektywny sposób na dodanie logiki specyficznej dla aplikacji bezpośrednio w szablonach. W kontekście zarządzania rolami, takie dyrektywy znacznie ułatwiają kontrolę nad tym, co i komu jest wyświetlane na stronach aplikacji.
Zabezpieczanie Tras i Praktyczne Wykorzystanie Dyrektyw Blade
Zaimplementowany system ról i nowo utworzone dyrektywy Blade pozwalają na skuteczną kontrolę dostępu zarówno na poziomie tras (routes) w backendzie, jak i w warstwie widoków w frontendzie. W tej sekcji omówimy, jak wykorzystać middleware checkRole
do zabezpieczania tras oraz jak użyć dyrektyw Blade do zarządzania treścią w zależności od roli użytkownika.
Zabezpieczanie Tras za Pomocą Middleware:
Middleware checkRole
, które stworzyliśmy wcześniej, może być teraz wykorzystane do ochrony określonych tras w aplikacji.
Route::get('/admin', function () {
// Tylko dla roli 'admin'
})->middleware('checkRole:admin');
W tym przykładzie, trasa /admin
jest dostępna tylko dla użytkowników z rolą 'admin’. Jeśli użytkownik nie posiada tej roli, zostanie zablokowany przez middleware i otrzyma komunikat o błędzie 403.
Wykorzystanie Dyrektyw Blade:
W widokach Blade możemy teraz skorzystać z dyrektywy @hasrole
do wyświetlania różnych części treści w zależności od roli użytkownika.
@hasrole('admin')
admin<br>
@endhasrole
@hasrole('user')
user<br>
@endhasrole
@guest
gość<br>
@endguest
@auth
zalogowany<br>
@endauth
Te dyrektywy pozwalają na dynamiczne dostosowywanie widoku. Na przykład, fragment oznaczony @hasrole('admin')
będzie widoczny tylko dla użytkowników z rolą 'admin’, a @hasrole('user')
tylko dla zwykłych użytkowników. Dodatkowo, Laravel oferuje wbudowane dyrektywy @guest
i @auth
, które pozwalają na sprawdzenie, czy użytkownik jest gościem (niezalogowanym) lub zalogowanym.
Dzięki tym technikom, możemy zapewnić, że pewne sekcje naszej aplikacji są dostępne tylko dla określonych użytkowników, zwiększając tym samym jej bezpieczeństwo i użyteczność. Jest to szczególnie ważne w przypadku stron administracyjnych, paneli zarządzania, czy innych obszarów wymagających określonych uprawnień.
Zarządzanie Rolami Użytkowników
Przed omówieniem zaawansowanych technik zarządzania rolami, które będą przedmiotem osobnego artykułu, warto zrozumieć podstawową metodę ręcznego dodawania ról użytkownikom. Ta metoda może być użyteczna w przypadkach, gdzie potrzebna jest szybka modyfikacja ról bez korzystania z dedykowanej funkcjonalności aplikacji.
Dostęp do Bazy Danych:
Aby ręcznie dodać role użytkownikom, musisz mieć dostęp do bazy danych twojej aplikacji Laravel. Możesz korzystać z narzędzi takich jak phpMyAdmin, Laravel Tinker, czy bezpośrednio z interfejsu linii poleceń SQL.
Znajdowanie Użytkowników i Ról:
Najpierw zidentyfikuj użytkownika, któremu chcesz przypisać rolę, oraz rolę, którą chcesz przypisać. Zazwyczaj będziesz operować na tabelach users
, roles
oraz role_user
.
Dodawanie Roli:
Aby dodać rolę, wprowadź odpowiedni rekord do tabeli role_user
. Na przykład, aby dodać rolę o ID 1 do użytkownika o ID 2, użyjesz polecenia SQL:
INSERT INTO role_user (user_id, role_id) VALUES (2, 1);
To polecenie utworzy powiązanie między użytkownikiem a rolą w tabeli pośredniej.
Pamiętaj, że metoda ręczna jest mniej bezpieczna i podatna na błędy, dlatego zalecane jest stosowanie dedykowanych funkcji aplikacji do zarządzania rolami, o czym więcej w naszym kolejnym artykule.
Podsumowanie
W tym artykule skupiliśmy się na tworzeniu i wdrażaniu systemu zarządzania rolami w aplikacji Laravel. Rozpoczynając od instalacji i konfiguracji użytkowników za pomocą Laravel Breeze, przeszliśmy przez proces tworzenia migracji i modeli, aż do implementacji seedera wypełniającego bazę danych domyślnymi rolami. Następnie zdefiniowaliśmy relacje w modelach i skoncentrowaliśmy się na tworzeniu middleware do sprawdzania ról, a także na praktycznym wykorzystaniu dyrektyw Blade do zarządzania treścią widoków w zależności od ról użytkowników. Ta kompleksowa ścieżka pozwoliła nam na zbudowanie solidnego i elastycznego systemu zarządzania uprawnieniami w aplikacji Laravel, zapewniając skuteczną kontrolę dostępu i bezpieczeństwo danych.
Pingback: Rozbudowa Systemu Zarządzanie Rolami w Laravelu - brylka.net
Super artykuł.
Przydałoby się nieco zaktualizować bo w laravel 11 Rejestracja Middleware odbywa się już inaczej. nie w pliku kernel.php tylko w pliku app.php w folderze bootstrap i powinna wyglądać tak:
->withMiddleware(function (Middleware $middleware) {
$middleware->alias([’checkRole’ => \App\Http\Middleware\CheckRole::class]);
})
Przydałoby się dopisać przy dodawaniu kodu w plikach jakie klasy importować za pomocą „use” bo dla początkującego może sprawić kłopot które są potrzebne (ja takowy miałem ale ogarnąłem;))
Artykuł na 5+
hej.
jak podczas logowania sprawdzić jaką rolę ma użytkownik i przekierować go na stronę odpowiednią dla niego np:
jeśli admin to admin.dashboard,
jeśli user to user.dashboard
itp.
Pozdrawiam.