Menu nawigacyjne uwzględniające uprawnienia, z egzekwowaniem dostępu po stronie serwera
Menu nawigacyjne uwzględniające uprawnienia poprawiają czytelność, ale bezpieczeństwo musi być na backendzie. Zobacz proste wzorce dla ról, polityk i bezpiecznego ukrywania w UI.

Jaki problem naprawdę rozwiązują menu świadome uprawnień
Kiedy ktoś mówi „ukryj przycisk”, zwykle ma na myśli jedną z dwóch rzeczy: zmniejszyć bałagan dla użytkowników, którzy nie mogą korzystać z funkcji, albo powstrzymać nadużycia. Tylko pierwszy cel jest realistyczny po stronie frontend.
Menu świadome uprawnień to głównie narzędzie UX. Pomagają komuś otworzyć aplikację i od razu zobaczyć, co może robić, bez trafiania na „Access denied” co drugi klik. Zmniejszają też obciążenie supportu, bo unikamy pytań typu „Gdzie zatwierdzam faktury?” albo „Dlaczego ta strona się wywala?”.
Ukrywanie UI to nie zabezpieczenie. To jasność.
Nawet ciekawski współpracownik może:
- Wpisać bezpośredni link do ukrytej strony, jeśli zna URL
- Otworzyć stary bookmark do ekranu admina
- Wywołać twoje API bezpośrednio skryptem lub narzędziem
- Modyfikować żądania z przeglądarki i próbować różne ID
Prawdziwy problem, który rozwiązują menu świadome uprawnień, to szczere wskazówki. Trzymają interfejs zgodny z rolą i kontekstem użytkownika, jednocześnie jasno pokazując, gdy coś jest niedostępne.
Dobry stan końcowy wygląda tak:
- Użytkownicy widzą głównie akcje sensowne dla nich i rzadko trafiają na niespodziewane błędy.
- Deweloperzy mają jedno wspólne źródło prawdy dla reguł dostępu, zamiast rozproszonych sprawdzeń.
- Zmiany produktowe są bezpieczniejsze, bo nowy element menu zmusza do decyzji, jakie wymaga uprawnienia.
- Bezpieczeństwo jest egzekwowane tam, gdzie to ważne: backend odrzuca zabronione akcje zawsze, nawet jeśli UI pokaże je przypadkowo.
Przykład: w małym CRM, Sales Rep powinien widzieć Leads i Tasks, ale nie User Management. Jeśli mimo to wklei URL zarządzania użytkownikami, strona powinna się zamknąć (fail closed), a serwer powinien zablokować każde próby listowania użytkowników czy zmiany ról.
Widoczność to nie autoryzacja
Widoczność to to, co interfejs decyduje się pokazać. Autoryzacja to to, co system faktycznie pozwoli, gdy żądanie trafi na serwer.
Menu świadome uprawnień zmniejsza zamieszanie. Jeśli ktoś nigdy nie powinien zobaczyć Billing lub Admin, ukrycie tych pozycji utrzymuje aplikację w porządku i zmniejsza liczbę zgłoszeń do supportu. Ale ukrycie przycisku nie jest zamkiem. Ludzie wciąż mogą spróbować wywołać endpoint używając dev tools, starego bookmarka lub skopiowanego żądania.
Praktyczna zasada: zdecyduj, jakie doświadczenie chcesz zapewnić, a potem egzekwuj regułę na backendzie bez względu na to, co robi UI.
Gdy decydujesz, jak zaprezentować akcję, trzy wzorce pokrywają większość przypadków:
- Ukryj gdy funkcja powinna być nieodkrywalna dla większości ról (np. narzędzia wewnętrzne).
- Wyłącz gdy funkcja istnieje, ale użytkownik teraz nie może jej użyć (np. Export wyłączony do czasu upgrade planu, do momentu wybrania rekordu lub podczas ładowania danych).
- Pokaż z wyjaśnieniem gdy użytkownikowi trzeba wytłumaczyć, dlaczego nie może kontynuować („Możesz przeglądać faktury, ale tylko Owners mogą edytować metody płatności”).
„Możesz przeglądać, ale nie edytować” jest częstym przypadkiem i warto projektować go jawnie. Traktuj jako dwie uprawnienia: jedno do czytania, jedno do zmiany. W menu możesz pokazać szczegóły klienta każdemu, kto ma prawa do odczytu, ale pokazywać Edytuj klienta tylko tym, którzy mają zapis. Na stronie renderuj pola w trybie tylko do odczytu i blokuj kontrolki edycji, ale pozwól stronie się załadować.
Najważniejsze: backend decyduje o wyniku końcowym. Nawet jeśli UI ukryje wszystkie akcje admina, serwer musi sprawdzać uprawnienia przy każdym wrażliwym żądaniu i zwracać jasne „not allowed”, gdy ktoś spróbuje.
Wybierz model uprawnień, który da się utrzymać
Najszybszy sposób na wdrożenie menu świadomych uprawnień to start z modelem, który zespół potrafi wyjaśnić jednym zdaniem. Jeśli nie potrafisz tego wytłumaczyć, nie utrzymasz go poprawnie.
Używaj ról do grupowania, nie do znaczenia. Admin i Support to przydatne kubełki. Ale gdy role zaczynają się mnożyć (Admin-West-Coast-ReadOnly), UI zamienia się w labirynt, a backend w zgadywankę.
Preferuj uprawnienia jako źródło prawdy co do tego, co ktoś może zrobić. Trzymaj je małe i oparte na akcjach, np. invoice.create lub customer.export. To skaluje się lepiej niż rozrost ról, bo nowe funkcje zwykle dodają nowe akcje, a nie nowe tytuły stanowisk.
Potem dodaj polityki (rules) dla kontekstu. Tu obsługujesz „może edytować tylko własny rekord” albo „może zatwierdzać faktury tylko poniżej 5 000”. Polityki zapobiegają tworzeniu kilkudziesięciu niemal identycznych uprawnień różniących się tylko warunkiem.
Utrzymywalna warstwowa struktura wygląda tak:
- Role grupują uprawnienia (funkcja w pracy)
- Uprawnienia opisują akcje (co)
- Polityki dodają kontekst (kiedy, które rekordy)
Nazewnictwo ma większe znaczenie, niż się wydaje. Jeśli UI mówi Export Customers, a API używa download_all_clients_v2, prędzej czy później ukryjesz złe rzeczy albo zablokujesz te, które trzeba. Trzymaj nazwy czytelne dla ludzi, spójne i współdzielone między frontendem a backendem:
- Używaj konsekwentnie
noun.verb(lubresource.action) - Dopasuj etykiety UI do intencji uprawnień, nie do wewnętrznych nazw kodu
- Utrzymuj zgodność starych nazw uprawnień przy refaktoryzacjach
Przykład: w CRM rola Sales może mieć lead.create i lead.update, ale polityka ogranicza aktualizacje do leadów, których właścicielem jest użytkownik. To utrzymuje menu czytelne, a backend surowy.
Krok po kroku: wdrożenie ról i uprawnień end-to-end
Menu świadome uprawnień działają dobrze, bo redukują bałagan i zapobiegają przypadkowym kliknięciom. Ale pomagają tylko wtedy, gdy backend pozostaje w kontroli. Traktuj UI jako wskazówkę, a serwer jako sędziego.
Zacznij od spisania tego, co chronisz. Nie stron, lecz akcji. Lista klientów jest inna niż eksport klientów czy usunięcie klienta. To kręgosłup menu, które nie stanie się tylko „teatrem bezpieczeństwa”.
Praktyczny przepis end-to-end
- Inwentaryzacja akcji w UI i API. Dla każdej funkcji wypisz konkretne operacje: read, create, update, delete, export, invite, zmiany billingowe, uruchamianie raportów admina.
- Zdefiniuj uprawnienia na serwerze jako źródło prawdy. Przechowuj mapowanie rola→uprawnienia w bazie (lub configu), i sprawiaj, żeby każdy handler API pytał „czy ten użytkownik ma uprawnienie X na zasobie Y?”.
- Zwróć mały payload capabilities do UI. Po logowaniu (lub odświeżeniu sesji) zwróć boole jak
canEditCustomers,canDeleteCustomers,canExport, lub kompaktową listę permission strings. Trzymaj to minimalne. - Egzekwuj sprawdzenia przy każdym zapisie i przy wrażliwych odczytach. Wszystkie mutacje muszą sprawdzać uprawnienia. Niektóre odczyty też (np. pensje, logi audytu, eksporty lub endpointy omijające normalne filtrowanie).
- Dodaj kilka testów skupionych na rolach. Wybierz 2–3 kluczowe role i przetestuj najwyższego ryzyka akcje. Przykład: Sales może tworzyć umowy, ale nie eksportować klientów; Admin może zapraszać użytkowników.
Mała, ale ważna zasada: nigdy nie ufaj pochodzącym z klienta flagom roli czy uprawnień. UI może ukrywać przyciski na podstawie capabilities, ale API wciąż musi odrzucać nieautoryzowane żądania.
Wzorce frontendu, które pozostają uczciwe
Menu świadome uprawnień powinno pomagać ludziom znaleźć, co mogą robić, a nie udawać, że egzekwuje zabezpieczenia. Frontend jest prowadnicą; backend jest zamkiem.
Buduj menu z jednego źródła prawdy
Zamiast rozsypywać sprawdzenia uprawnień po każdym przycisku, zdefiniuj nawigację w jednym configu, który zawiera wymagane uprawnienie dla każdej pozycji, a potem renderuj z tego configu. To utrzymuje reguły czytelne i zmniejsza ryzyko zapomnianych sprawdzeń w rzadkich częściach UI.
Prosty wzorzec wygląda tak:
const menu = [
{ label: "Contacts", path: "/contacts", requires: "contacts.read" },
{ label: "Export", action: "contacts.export", requires: "contacts.export" },
{ label: "Admin", path: "/admin", requires: "admin.access" },
];
const visibleMenu = menu.filter(item => userPerms.includes(item.requires));
Wol preferować ukrywanie całych sekcji (np. Admin) niż rozsypywanie sprawdzeń przy każdym linku do admina. Mniej miejsc do popełnienia błędu.
Uczciwe stany: ukryte vs wyłączone
Ukrywaj elementy, gdy użytkownik nigdy nie będzie mógł ich użyć. Wyłączaj elementy, gdy użytkownik ma uprawnienie, ale brakuje kontekstu.
Przykład: Usuń kontakt powinien być wyłączony, dopóki nie wybrano kontaktu. To to samo uprawnienie, po prostu brakuje kontekstu. Gdy wyłączasz, dodaj krótkie „dlaczego” obok kontrolki (tooltip, pomocniczy tekst lub notka): Wybierz kontakt, aby usunąć.
Zasady, które się sprawdzają:
- Ukrywaj, gdy użytkownik nie ma uprawnienia.
- Wyłączaj, gdy użytkownik ma uprawnienie, ale nie wybrano elementu, formularz jest niepoprawny lub dane się ładują.
- Nigdy nie traktuj local storage jako prawdy dla uprawnień. To tylko cache.
- Ponownie sprawdzaj uprawnienia po logowaniu, zmianie roli lub przełączeniu konta.
Egzekwowanie na backendzie, którego nie da się obejść
Ukrycie pozycji w menu pomaga skupić uwagę, ale nic nie zabezpiecza. Backend musi być ostatecznym sędzią, bo żądania można powtarzać, edytować lub wywołać spoza UI.
Dobra zasada: każda akcja zmieniająca dane potrzebuje jednego miejsca sprawdzenia autoryzacji, przez które przechodzi każde żądanie. Może to być middleware, wrapper handlera lub mała warstwa polityk, którą wywołujesz na początku każdego endpointu. Wybierz jedną metodę i się jej trzymaj, inaczej pominiesz ścieżki.
Umieść sprawdzenie na ścieżce żądania
Trzymaj autoryzację oddzielnie od walidacji wejścia. Najpierw zadaj pytanie: „czy ten użytkownik może to zrobić?”, potem waliduj payload. Jeśli walidujesz najpierw, możesz ujawnić szczegóły (np. że dany ID istnieje) komuś, kto w ogóle nie powinien wiedzieć, że akcja jest możliwa.
Wzorzec, który skaluje się dobrze:
- Uwierzytelnij wywołującego i zbuduj jasną tożsamość (user id, org id, role, permissions).
- Wczytaj kontekst zasobu potrzebny do autoryzacji (często tylko owner id lub org id).
- Wywołaj jedną funkcję polityki (np.
Can(user, "invoice.delete", invoice)). - Jeśli odmowa, przerwij i zwróć odpowiedni status.
- Dopiero potem waliduj i wykonuj logikę biznesową.
Zwracaj jasne, spójne odpowiedzi
Używaj kodów statusu, które pomagają frontendowi i logom:
401 Unauthorizedgdy wywołujący nie jest zalogowany.403 Forbiddengdy jest zalogowany, ale nie ma uprawnień.
Uważaj z 404 Not Found jako maskowaniem. Może być przydatne, by nie ujawniać istnienia zasobu, ale jeśli mieszasz to losowo, debugowanie stanie się trudne. Wybierz spójną regułę per typ zasobu.
Upewnij się, że ta sama autoryzacja uruchamia się niezależnie od tego, czy akcja przyszła z kliknięcia przycisku, aplikacji mobilnej, skryptu czy bezpośredniego wywołania API.
Na koniec, loguj odmowy w celach debugowania i audytu, ale trzymaj logi bezpieczne. Rejestruj kto, jaka akcja i jaki ogólny typ zasobu. Unikaj zapisów wrażliwych pól, pełnych payloadów czy sekretów.
Edge case’y, które decydują o jakości projektu
Większość błędów z uprawnieniami pojawia się, gdy użytkownicy robią coś, czego menu nie przewidziało. Dlatego menu są użyteczne, ale tylko jeśli zaprojektujesz ścieżki, które je omijają.
Deep linki i „ukryte” ekrany
Jeśli menu ukrywa Billing dla danej roli, użytkownik nadal wklei zapisany URL lub otworzy go z historii przeglądarki. Traktuj każde ładowanie strony jak świeże żądanie: pobierz aktualne uprawnienia użytkownika i nie pozwól ekranowi ładować chronionych danych, gdy brak uprawnienia. Przyjazny komunikat „Nie masz dostępu” jest OK, ale realną ochroną jest, że backend nic nie zwróci.
Bezpośrednie wywołania API i endpointy masowe
Każdy może wywołać twoje API z dev tools, skryptu lub innego klienta. Sprawdzaj uprawnienia na każdym endpointzie, nie tylko na ekranach admina. Łatwo przeoczyć ryzyko akcji masowych: pojedynczy /items/bulk-update może pozwolić nie-adminowi zmieniać pola, których w UI nie widzi.
Role mogą też zmieniać się w trakcie sesji. Jeśli admin odbiera uprawnienie, użytkownik może mieć nadal stary token lub zcache’owane menu. Używaj tokenów krótkotrwałych lub server-side lookup uprawnień i obsłuż 401/403 odświeżeniem uprawnień i aktualizacją UI.
Współdzielone urządzenia to kolejna pułapka: zcache’owany stan menu może przeciekać między kontami. Przechowuj widoczność menu kluczem user ID lub w ogóle jej nie persistuj.
Pięć testów wartch uruchomienia przed wydaniem:
- Otwórz deep link do ukrytej strony zalogowany jako ograniczona rola
- Wywołaj chronione API kopiując żądanie z dev tools
- Zmień rolę użytkownika podczas jego aktywności, potem powtórz akcje
- Wyloguj się, zaloguj jako inny użytkownik i sprawdź czy menu się resetuje
- Przetestuj endpointy masowe z mieszanymi polami dozwolonymi i zabronionymi
Przykład: proste menu CRM z rzeczywistym egzekwowaniem
Wyobraź sobie wewnętrzny CRM z trzema rolami: Sales, Support i Admin. Wszyscy się logują i aplikacja pokazuje lewy pasek menu, ale menu to tylko wygoda. Rzeczywiste bezpieczeństwo to, co serwer pozwala.
Oto prosty zestaw uprawnień, który pozostaje czytelny:
- Leads: view, create, edit, delete, export
- Tickets: view, create, edit, assign
- Billing: view, edit
- Users: view, manage
UI zaczyna od zapytania backendu o dozwolone akcje aktualnego użytkownika (często jako lista permission strings) oraz podstawowy kontekst jak user id i zespół. Menu budowane jest z tego. Jeśli nie masz billing.view, nie widzisz Billing. Jeśli masz leads.export, widzisz przycisk Export na ekranie Leads. Jeśli możesz edytować tylko swoje leady, przycisk Edit może się pojawić, ale powinien być wyłączony lub pokazywać jasny komunikat, gdy lead nie należy do ciebie.
Teraz ważna część: każdy endpoint akcji egzekwuje te same reguły.
Przykład: Sales może tworzyć leady i edytować leady, których jest właścicielem. Support może przeglądać tickety i przypisywać je, ale nie może dotykać billing. Admin może zarządzać użytkownikami i billingiem.
Gdy ktoś próbuje usunąć lead, backend sprawdza:
- Czy użytkownik ma
leads.delete? - Jeśli reguła to only-own, czy
lead.owner_id == user.id? - Jeśli lead jest zablokowany (np. już zafakturowany), czy usuwanie jest zabronione dla wszystkich poza Admin?
Nawet jeśli Support ręcznie wywoła endpoint usunięcia, dostanie forbidden. Ukryte menu nigdy nie było ochroną — decyzję podjął backend.
Typowe błędy i pułapki
Największa pułapka to myślenie, że zadanie jest zakończone, gdy menu wygląda poprawnie. Ukrycie przycisków zmniejsza zamieszanie, ale nie zmniejsza ryzyka.
Najczęstsze błędy:
- „Niewidoczne” staje się „niemożliwe”. Ktoś i tak może wywołać API bezpośrednio, użyć starego URL lub narzędzi developerskich. Traktuj ukrycie w UI jako wygodę, nie jako bramkę.
- Uprawnienia sprawdzane tylko w UI. Jeśli frontend decyduje kto może usunąć rekord, już przegrałeś. Backend musi być ostatecznym sędzią każdej chronionej akcji.
- Jedna wielka flaga
isAdmindla wszystkiego. Szybko się rozprzestrzenia. Wkrótce każda wyjątek to osobny przypadek, a nikt nie potrafi wyjaśnić zasad dostępu. - Ufać klientowi w podawaniu roli. Nigdy nie akceptuj
role,isAdminanipermissionsz przeglądarki jako prawdy. Wyprowadzaj tożsamość i dostęp z własnej sesji lub tokena, potem sprawdzaj role/uprawnienia po stronie serwera. - Zapominanie o uprawnieniach do odczytu. Zespoły skupiają się na zapisie (create, update, delete), ale wycieki danych zwykle pochodzą z odczytów. Listowanie klientów, przegląd faktur, eksport CSV i wyszukiwanie często też wymagają sprawdzeń.
Konkretny przykład: ukrywasz Export leads dla nie-managerów. Jeśli endpoint eksportu nie sprawdza uprawnień, każdy, kto zgadnie żądanie (lub skopiuje je od kolegi), może pobrać plik.
Szybka lista kontrolna przed uruchomieniem
Zanim wypuścisz menu świadome uprawnień, zrób ostatni przegląd skupiony na tym, co użytkownicy faktycznie mogą zrobić, a nie tylko na tym, co widzą.
Przejdź aplikację jako każda główna rola i wykonaj ten sam zestaw akcji. Zrób to w UI i także wywołując endpointy bezpośrednio (lub korzystając z dev tools), aby upewnić się, że serwer jest źródłem prawdy.
Checklist:
- Dla każdej chronionej akcji potwierdź, że istnieje sprawdzenie autoryzacji po stronie serwera w miejscu wykonania (nie tylko przy budowaniu menu).
- Spraw, by UI renderowało akcje z danych capabilities pochodzących z serwera (np. can-list z sesji lub endpointu permissions), zamiast zgadywać po nazwach ról.
- Zweryfikuj, że UI traktuje forbidden jako normalny stan: pokaż jasny komunikat, utrzymaj stabilność strony i unikaj pozostawiania użytkownika w zepsutym stanie.
- Testuj zmiany ról i uprawnień. Gdy admin zmienia dostęp, powinno to działać szybko i przewidywalnie (odświeżenie tokena, unieważnienie sesji lub wersjonowanie uprawnień).
- Uruchom kilka testów wysokiej wartości obejmujących role i akcje, które mają wpływ na pieniądze, eksporty, usunięcia i ustawienia admina.
Praktyczny sposób na znalezienie luk: wybierz jeden „niebezpieczny” przycisk (usuń użytkownika, eksport CSV, zmiana billing) i prześledź go end-to-end. Element menu powinien być ukryty gdy trzeba, API powinno odrzucić nieautoryzowane wywołania, a UI powinno się ładnie odzyskać przy 403.
Następne kroki: bezpiecznie wypuszczać bez zwalniania tempa
Zacznij od małego zakresu. Nie potrzebujesz idealnej matrycy dostępu na dzień pierwszy. Wybierz kilka najważniejszych akcji (view, create, edit, delete, export, manage users), przypisz je do ról, i idź dalej. Gdy pojawi się nowa funkcja, dodaj tylko nowe akcje, które wprowadza.
Zanim zaczniesz budować ekran, zrób krótką sesję planowania i wypisz akcje, nie strony. Pozycja menu jak Invoices kryje wiele akcji: view list, view details, create, refund, export. Spisanie tego wcześniej ułatwia pracę UI i backendowi oraz zapobiega błędowi polegającemu na zablokowaniu strony przy pozostawieniu ryzykownego endpointu bez ochrony.
Gdy refaktoryzujesz reguły dostępu, traktuj to jak ryzykowną zmianę: miej siatkę bezpieczeństwa. Snapshoty pozwalają porównać zachowanie przed i po. Jeśli rola nagle straci dostęp, lub zyska niepowinna mieć, rollback jest szybszy niż hot-fix w produkcji, gdy użytkownicy są zablokowani.
Proste zasady wydawnicze, które pomagają szybko działać bez zgadywania:
- Napisz listę akcji dla funkcjonalności i nazwij każde uprawnienie.
- Dodaj sprawdzenia na backendzie najpierw, potem podłącz widoczność UI do tych samych uprawnień.
- Testuj jedną rolę dozwoloną i jedną zabronioną dla każdej ryzykownej akcji.
- Loguj odmowy (bez danych wrażliwych), aby wykrywać luki.
- Zrób snapshot przed rolloutem, by móc szybko się cofnąć.
Jeśli budujesz z platformą chatową jak Koder.ai (koder.ai), ta sama struktura nadal obowiązuje: definiuj uprawnienia i polityki raz, pozwól UI czytać capabilities z serwera i wymuszaj sprawdzenia po stronie serwera w każdym handlerze.
Często zadawane pytania
Co właściwie rozwiązują menu świadome uprawnień?
Menu świadome uprawnień w większości przypadków rozwiązują czytelność, nie bezpieczeństwo. Pomagają użytkownikom skupić się na tym, co mogą zrobić, zmniejszają liczbę niepotrzebnych kliknięć i ograniczają pytania do supportu typu „dlaczego to widzę?”.
Bezpieczeństwo wciąż musi być egzekwowane po stronie serwera, bo każdy może spróbować wejść przez bezpośredni link, stary bookmark lub wywołać API niezależnie od tego, co pokazuje UI.
Kiedy powinienem ukryć element menu, a kiedy go wyłączyć?
Ukrywaj, gdy funkcja powinna być praktycznie nieodkrywalna dla danej roli i nie ma oczekiwanej ścieżki jej użycia.
Wyłączaj, gdy użytkownik może mieć dostęp, ale brakuje mu teraz kontekstu — np. nie wybrano rekordu, formularz jest nieprawidłowy lub dane się ładują. Jeśli wyłączasz, dołącz krótkie wyjaśnienie, by kontrolka nie wyglądała na zepsutą.
Dlaczego „ukrycie przycisku” to nie jest zabezpieczenie?
Bo widoczność to nie to samo co autoryzacja. Użytkownik może wkleić URL, otworzyć zapisany ekran admina albo wywołać API poza interfejsem.
Traktuj UI jako wskazówkę. Traktuj backend jako ostatecznego sędziego dla każdej wrażliwej operacji.
Skąd frontend ma wiedzieć, co użytkownik może zrobić?
Twój serwer powinien zwracać niewielką odpowiedź z „capabilities” po zalogowaniu lub odświeżeniu sesji, opartą na serwerowych sprawdzeniach uprawnień. UI renderuje menu i przyciski na podstawie tego ładunku.
Nie ufaj flagom pochodzącym z przeglądarki, jak isAdmin; oblicz uprawnienia na serwerze z uwierzytelnioną tożsamością.
Jaki jest najprostszy sposób end-to-end, by wdrożyć uprawnienia?
Zacznij od spisu akcji, nie stron. Dla każdej funkcji rozbij operacje na read, create, update, delete, export, invite, zmiany billingowe itp.
Następnie egzekwuj każdą akcję w backendowym handlerze (lub middleware) zanim zostanie wykonana. Podłącz menu do tych samych nazw uprawnień, aby UI i API pozostały spójne.
Czy używać ról czy uprawnień jako głównego modelu?
Praktyczna zasada: role to wiadra, uprawnienia to źródło prawdy. Trzymaj uprawnienia małe i oparte na akcjach (np. invoice.create) i przypinaj je do ról.
Jeśli role zaczynają mnożyć się, by zakodować warunki (region, tylko do odczytu), przenieś te warunki do polityk zamiast tworzyć kolejne warianty ról.
Jak obsłużyć „może zobaczyć, ale nie może edytować” i inne warunkowe dostępy?
Użyj polityk do reguł kontekstowych, takich jak „edytuj tylko własny rekord” albo „zatwierdzaj faktury poniżej progu”. Dzięki temu lista uprawnień pozostaje stabilna, a backend ocenia reguły na podstawie kontekstu zasobu (np. owner_id czy org_id).
Czy naprawdę potrzebuję sprawdzeń uprawnień też dla endpointów do odczytu?
Nie zawsze. Ochrona odczytów jest konieczna, gdy dane są wrażliwe lub gdy endpoint omija normalne filtrowanie — np. exporty, logi audytu, dane płacowe, lista użytkowników admina itp.
Dobra zasada: wszystkie zapisy muszą być sprawdzane, a wrażliwe odczyty też powinny być chronione.
Jak uniknąć dziur bezpieczeństwa przy akcjach masowych i „power” endpointach?
Endpointy masowe łatwo przeoczyć, bo pojedyncze wywołanie może zmienić wiele rekordów lub pól. Użytkownik może być zablokowany w UI, ale wciąż wywołać /items/bulk-update bezpośrednio.
Sprawdzaj uprawnienia dla akcji masowej i dodatkowo waliduj, które pola dana rola może zmieniać, by nie dopuścić do edycji ukrytych pól.
Co zrobić, gdy role zmieniają się w trakcie sesji albo cache UI jest nieaktualny?
Zakładaj, że uprawnienia mogą się zmienić w trakcie sesji. Przy 401/403 UI powinno obsłużyć to jak normalny stan: odświeżyć capabilities, zaktualizować menu i wyświetlić jasny komunikat.
Nie zapisuj widoczności menu w sposób, który może przeciekać między kontami na współdzielonych urządzeniach; jeśli cache’ujesz, kluczkuj go identyfikatorem użytkownika lub w ogóle go nie persistuj.