1. Jak nie należy robić 💅
Macierz dostępu to nie „tabela ról dla samej tabeli". To kompaktowa forma decyzji projektowej. Pomaga jeszcze przed konfiguracją zobaczyć, jakie strefy naprawdę żyją wewnątrz produktu i jakie działania wymagają nie tylko autentykacji, lecz ownership lub przywilejów.
Szczególnie przydatne jest to, że macierz zmusza do dyskutowania o działaniach, a nie tylko ścieżkach. Ten sam zasób może mieć różne reguły dla odczytu, aktualizacji, publikacji i usuwania. Jeśli nie jest to ujawnione jawnie, mózg zaczyna się lenić i wszystko sprowadza do jednej grubej etykietki „no zamknięty endpoint".
W projekcie Secure Content Platform API macierz składa się dobrze już na pierwszym poziomie, bo sama domena jest wystarczająco kompaktowa. I właśnie na tym polega jej siła: na małym projekcie widać prawie cały kurs.
2. Podstawowa access matrix Secure Content Platform API
Poniżej – startowa macierz projektu. To jeszcze nie gotowy SecurityFilterChain, nie adnotacje i nie kod enforcement. To mapa dostępu w słowach biznesowych.
| Endpoint | Działanie | Podstawowa strefa | Dodatkowy warunek |
|---|---|---|---|
| GET /api/public/articles | czytać opublikowane artykuły | public | brak |
| GET /api/public/articles/{slug} | czytać jeden opublikowany artykuł | public | brak |
| GET /api/me | pobrać bieżącego użytkownika | authenticated | caller musi być znany systemowi |
| GET /api/me/profile | czytać swój profil | authenticated | trasa jest już self-scoped |
| PATCH /api/me/profile | aktualizować swój profil | authenticated | trasa jest już self-scoped |
| GET /api/drafts | czytać listę swoich szkiców | authenticated | lista budowana od bieżącego callera |
| GET /api/drafts/{id} | czytać konkretny szkic | owner-only | obiekt musi należeć do callera |
| PATCH /api/drafts/{id} | edytować szkic | owner-only | obiekt musi należeć do callera |
| POST /api/drafts/{id}/submit | wysłać szkic do moderacji | owner-only | można wysyłać tylko swój draft |
| GET /api/editor/review-queue | widzieć kolejkę moderacji | editor | wymagana rola EDITOR lub ADMIN |
| POST /api/editor/drafts/{id}/publish | publikować materiał | editor | wymagana rola EDITOR lub ADMIN |
| PATCH /api/admin/users/{id}/roles | zmieniać role użytkownika | admin | wymagana rola ADMIN |
| PATCH /api/admin/users/{id}/lock | blokować lub odblokowywać użytkownika | admin | wymagana rola ADMIN |
| POST /api/auth/register | rejestrować nowego użytkownika | public | brak |
| POST /api/auth/login | logować się do systemu | public | brak |
Taka tabela ma jedną mocną właściwość: usuwa mgłę. Od razu widać, że /api/me/profile i /api/drafts/{id} wyglądają podobnie tylko z zewnątrz. W pierwszym przypadku self-scope jest już wbudowany w design trasy. W drugim trasa sama w sobie nie wie, czyj dokładnie obiekt wybrano po id, i ownership staje się obowiązkową częścią reguły.
Od razu widać i coś innego: formuła „prawie wszystko authenticated" tu już nie działa jako uczciwy opis systemu. W domenie jest publiczna witryna, strefa osobista, przypadki owner-only na poziomie obiektu, operacje redaktorskie i działania administracyjne. To już pełnoprawny model dostępu, a nie kosmetyczna nadbudowa.
3. Jedna kolumna role to za mało
Początkujący bardzo lubią zamieniać macierz dostępu w „tabelę ról". To zrozumiały instynkt: role wyglądają prosto i wygodnie. Ale gdy tylko w systemie pojawia się reguła „swój obiekt / cudzy obiekt", sama rola już nie wystarczy.
Wyobraź sobie dwóch użytkowników z rolą USER. Obaj są uwierzytelnieni, obaj uczciwi, obaj logują się poprawnie. Ale to nie znaczy, że każdy z nich powinien czytać i edytować dowolny draft po dowolnym id. Tu reguła zależy nie tylko od roli, lecz i od relacji między callerem a obiektem.
Dlatego dobra macierz prawie zawsze zawiera nie tylko kolumnę „kto", ale i kolumnę „jaki dodatkowy warunek". Gdzieś ten warunek jest pusty. Gdzieś brzmi „trasa self-scoped". Gdzieś – „obiekt musi należeć do callera". Właśnie w tym miejscu macierz przestaje być grubą „tabelą ról" i staje się mapą realnych decyzji security 📌
Jest jeszcze jedna subtelność. Ta sama ścieżka przy różnych metodach HTTP może oznaczać różne działania. GET /api/public/articles/{slug} i DELETE /api/public/articles/{slug} to nie jest „ten sam zasób, więc mniej więcej tak samo". Metoda zmienia tu sens biznesowy, a razem z nią prawie na pewno zmienia się i reguła dostępu.
4. Szablon szybkiego audytu dostępu dla każdego API
Poniżej – właśnie ten artefakt, który warto zabrać ze sobą już dziś. Nie jest przywiązany tylko do naszego projektu. To krótki szablon audytu, który można zastosować do każdego API, przy którym pracujesz lub się uczysz.
| Krok | Pytanie | Co powinieneś odnotować |
|---|---|---|
| 1 | Jakie to działanie w słowach biznesowych? | nie „endpoint istnieje", lecz „co system naprawdę robi" |
| 2 | Czy można wywołać to działanie anonimowo? | public lub nie public |
| 3 | Jeśli anonimowo nie można, jakiego callera oczekuje system? | co najmniej authenticated, a niekiedy konkretna rola |
| 4 | Czy istnieje związek callera z konkretnym obiektem? | ownership, self-scope, „swój / cudzy" |
| 5 | Czy to wpływa na cudze dane, moderację lub zarządzanie systemem? | poziom editor / admin lub podobny przywilej |
To bardzo prosta tabela, ale właśnie w niej tkwi praktyczna siła. Nie wymaga od ciebie znajomości wszystkich szczegółów Spring Security już teraz. Wymaga tylko uczciwego opisania logiki dostępu. A właśnie tego najczęściej brakuje na wczesnym etapie projektowania.
Jeśli używasz tego szablonu regularnie, szybko zacznie wyłapywać te miejsca, które zespół zazwyczaj pomija: ownership na poziomie obiektu, zbyt grube authenticated tam, gdzie potrzeba owner-only, i operacje administracyjne zamaskowane pod „zwykły CRUD".
5. Na jednej macierzy już widać cały kurs ✨
I tu następuje przyjemny moment: na jednej startowej macierzy widać już, po co cały kurs w ogóle istnieje i jak jest zbudowany modułami.
| Co widać w macierzy już teraz | Co kurs doda dalej |
|---|---|
| są strefy publiczne i niepubliczne | starter-security, secure-by-default i pierwsze jawne reguły na poziomie żądania |
| system potrzebuje znanego callera | users, passwords, session-based security i klasyczny model stanowy |
| są różnice owner/editor/admin | request-level authorization, method security i biznesowe reguły dostępu |
| caller musi stać się realny, a nie edukacyjny | DB-backed users i normalny model użytkownika |
| część klientów będzie chciała trybu bezstanowego | JWT fundamentals i przejście do stateless security |
| dostęp trzeba nie tylko skonfigurować, lecz i utrzymać | testy security, hardening i troubleshooting |
To bardzo dobry efekt dla pierwszego poziomu. Jeszcze nie pisałeś dużej konfiguracji, nie dotykałeś filter chain ani nie budowałeś JWT. Ale już widać, że kurs nie rozpada się na przypadkowe tematy. Kolejno rozwijał jeden i ten sam obraz dostępu w działający backend.
Właśnie dlatego Secure Content Platform API to dobra domena edukacyjna. Jest mała, ale nie zabawkowa. Na niej widać prawie wszystko, co potem realnie spotka się w zwykłej aplikacji: publiczny odczyt, bieżący użytkownik, obiekty owner-only, strefa redaktorska, działania admina, potem users, session, DB, JWT i testy. To już nie tylko wstępna rozmowa. To mapa całej dalszej drogi.
6. Czego kurs świadomie nie próbuje pokryć
Zaufanie do kursu rośnie mocno, gdy ma on wyraźnie nazwane granice. Dlatego ważne jest powiedzenie od razu: ten kurs nie próbuje za pierwszym razem zamknąć całej światowej agendy security.
Nie będzie tu pełnoprawnego traktu OAuth2 / OIDC, zewnętrznych dostawców tożsamości, SSO, gateway security, rozproszonego przekazywania tokenów i mikroserwisowej platformowej egzotyki. Nie dlatego, że te tematy nie są potrzebne. Lecz dlatego, że najpierw trzeba zbudować stabilny obraz wewnątrz zwykłego backendu Spring Boot: zrozumieć request lifecycle, users, passwords, reguły żądań, sprawdzenia owner, modele stanowy i bezstanowy.
Właśnie dlatego kurs tak dobrze stoi w linii. Po Spring Boot i REST API Design dodaje brakującą warstwę dostępu. A po nim logicznie można iść w Spring Security Advanced: OAuth2 / OIDC, jeśli zadanie produktowe naprawdę wymaga zewnętrznej platformy tożsamości. Taka granica czyni kurs nie słabszym, lecz uczciwszym.
7. Typowe błędy 🚧
Błąd nr 1: oznaczać prawie wszystko jako authenticated.
To bardzo częsta „wygodna" degradacja macierzy. Wydaje się, jakbyś już zamknął API przed anonimem i można żyć dalej. Ale razem z tym tracą się przypadki ownership, granice editor/admin i realne różnice między działaniami.
Błąd nr 2: trzymać macierz tylko w głowach zespołu.
Przez pierwsze kilka dni jeszcze jakoś to działa. Potem pojawiają się nowe trasy, nowe osoby, nowe założenia i projekt zaczyna sobie samemu przeczyć. Jawna macierz jest potrzebna właśnie po to, żeby polityka dostępu była widoczna, a nie ustna.
Błąd nr 3: próbować wyrazić ownership wyłącznie przez role.
Rola USER nie wie, czyj to obiekt. Jeśli macierz nie potrafi odnotować dodatkowego warunku „caller jest właścicielem", znaczy to, że jest jeszcze zbyt gruboziarnista dla realnego backendu.
Błąd nr 4: myśleć tylko ścieżkami i zapominać o działaniach i metodach HTTP.
Jeden zasób może mieć zupełnie różne reguły dla GET, PATCH, POST i DELETE. Macierz, która widzi tylko ścieżkę i nie widzi działania, prędzej czy później zacznie ukrywać realne różnice dostępu.
GO TO FULL VERSION