Przejdź do treści
juz-ide.pl blog
Wróć

Autoryzacja, która nie pyta o rolę

Paweł G.
3 min czytania
Autoryzacja, która nie pyta o rolę
Temat Technologia fundamenty

Przez lata pisałem if (user.role === 'admin'). Wyglądało rozsądnie. Działało. Aż do dnia, kiedy chciałem dodać nową rolę i musiałem szukać tego warunku w dwudziestu miejscach kodu.

Problem, który miałem

juz-ide to platforma sąsiedzka. Jeden mieszkaniec Starachowic może być jednocześnie: użytkownikiem szukającym usług, usługodawcą oferującym pomoc, moderatorem swojej dzielnicy, administratorem dzielnicy. I jutro ta sama osoba może dostać nowe uprawnienia albo je stracić.

Gdybym pisał if (user.role === 'moderator' || user.role === 'admin') przy każdym endpoincie — sto endpointów, sto miejsc do zmiany przy każdej ewolucji uprawnień.

Poza tym role to coraz słabsza abstrakcja, gdy produkt rośnie. „Moderator” może moderować posty, ale nie może usuwać kont. „Admin dzielnicy” może zarządzać wszystkim w swojej dzielnicy, ale nie może nic zrobić w sąsiedniej. Rola przestaje wystarczać.

Zmiana myślenia: akcja + obiekt

Sierpień 2025, implementując system autoryzacji CASL, zmieniłem sposób myślenia.

Zamiast pytać „kim jest użytkownik?”, system pyta: „Czy ten użytkownik może wykonać tę akcję na tym obiekcie?”

Konkretnie: „czy może utworzyć ogłoszenie?” — albo tak, albo nie. Żadnego sprawdzania nazwy roli w środku.

Role zostają, ale wyłącznie jako definicja zestawu uprawnień. Kiedy użytkownik loguje się, system wylicza jego uprawnienia z jego ról i weryfikacji adresu. Reszta kodu nie wie, że istnieje coś takiego jak „moderator” — widzi tylko „może albo nie może”.

Dlaczego to ważne dla lokalnej aplikacji

juz-ide.pl to platforma, gdzie ten sam człowiek żyje jednocześnie w kilku rolach. Elektryczny z dzielnicy Michałów jest usługodawcą, mieszkańcem i może zostać moderatorem. Jego uprawnienia zmieniają się w czasie — weryfikacja adresu, nadanie roli przez urzędnika.

System, który każdą zmianę uprawnień obsługuje w jednym miejscu, a nie w dwudziestu — to nie akademicka elegancja. To kwestia tego, że za pół roku będę w stanie to utrzymać sam.

Ostatecznie chodzi o coś bardzo ludzkiego: ktoś poda swój adres albo odpisze obcemu z sąsiedztwa tylko wtedy, gdy poczuje, że nikt nie obejdzie się z tym byle jak. Precyzja w uprawnieniach jest mało widowiskowa, ale to na niej siada — albo nie siada — całe to zaufanie.

Biblioteka CASL i jak to działa architektonicznie

Do implementacji używam biblioteki CASL — open-source, TypeScript-first. Pozwala definiować uprawnienia deklaratywnie i sprawdzać je bez znajomości struktury ról w każdym punkcie aplikacji.

Kluczowe pojęcia:

  • Action — co chcesz zrobić (CREATE, READ, UPDATE, DELETE, MANAGE)
  • Subject — na jakim typie zasobu (ogłoszenie, profil, wpis…)
  • Condition — dodatkowy warunek (np. tylko dla zasobów, których jesteś właścicielem)
  • MANAGE — specjalna akcja oznaczająca „wszystko na tym obiekcie”, używana wyłącznie dla operacji administracyjnych na cudzych zasobach

Role to tylko sposoby grupowania zestawów uprawnień. Runtime operuje wyłącznie na parach Akcja + Obiekt.



Poprzedni wpis
PII jako wartość, nie jako string
Następny wpis
Od 21 kontekstów do 6: lekcja o over-engineeringu