JavaRush /Курси /Spring Security /Перше знайомство зі Spring Security

Перше знайомство зі Spring Security

Spring Security
Рівень 1 , Лекція 0
Відкрита

1. П’ять обробників, п’ять рівнів довіри

На рівні Spring MVC усі ендпоінти спершу виглядають однаково: метод контролера, анотація, шлях, HTTP-метод. Але щойно ви дивитеся на них крізь призму продукту, вони перестають бути рівними. Подивіться на такий набір маршрутів:

@GetMapping("/api/public/articles")
@GetMapping("/api/me")
@GetMapping("/api/drafts/{id}")
@PostMapping("/api/editor/drafts/{id}/publish")
@PatchMapping("/api/admin/users/{id}/roles")

Для фреймворку це просто п’ять обробників. Для бізнесу — п’ять різних рівнів довіри. Публічні статті мають бути доступними без входу в систему. Профіль поточного користувача вже потребує відомого системі користувача. Чернетка за довільним id одразу ставить питання «своя чи чужа». Публікація чужого матеріалу — це редакторський привілей. Зміна ролей — суто адміністративна зона. Застосунок один, стек один, кодова база одна — а логіка доступу вже різна.

Це хороший момент, щоб зробити перший крок до мислення про безпеку. Ендпоінт — це не лише «шматок бізнес-функції, доступний через HTTP». Це ще й брама в систему, а в кожної брами завжди є правила допуску. Якщо вони не описані явно, система не стає просто «тимчасово без security». Вона стає системою, де занадто багато тримається на мовчазних припущеннях.

2. Швидкий аудит проєкту як інженерна карта

Щоб не говорити надто загально, корисно вже зараз подивитися на проєкт крізь призму доступу. Нижче — не фінальна конфігурація і не код Spring Security, а лише чесний аудит: які зони взагалі живуть усередині одного API.

Ендпоінт Що робить Тип доступу
GET /api/public/articles повертає опубліковані статті public
GET /api/me повертає дані поточного користувача authenticated
GET /api/drafts/{id} читає конкретну чернетку owner-only
POST /api/editor/drafts/{id}/publish публікує матеріал після модерації editor
PATCH /api/admin/users/{id}/roles змінює ролі користувача admin

Ключове тут не самі рядки таблиці, а те, що це один API, а не п’ять різних систем. Багато початківців уперше по-справжньому відчувають security саме в цей момент: виявляється, «просто зробити CRUD» недостатньо, тому що в межах одного домену одночасно живуть публічні сценарії, особисті сценарії, правила володіння та привілейовані дії.

Саме тому курс починається не з JWT і не з набору анотацій. Спочатку потрібно навчитися бачити неоднорідність доступу всередині звичайного бекенд-застосунку. Поки цього не видно, будь-який security-фреймворк здаватиметься або магією, або зайвою бюрократією.

3. Ці зони зʼявляються майже в будь-якому бекенді

public зʼявляється там, де система має бути видимою ззовні. У нашому проєкті це опубліковані статті. Якщо користувач просто хоче читати відкритий контент, бекенд не зобовʼязаний спершу влаштовувати йому допит із пристрастю. Публічна зона — це не «дірка», а нормальна частина продукту, якщо вона спроєктована свідомо.

authenticated зʼявляється там, де дія вже не має сенсу без користувача, відомого системі. Маршрут на кшталт /api/me взагалі не можна коректно реалізувати, якщо система не розуміє, хто робить запит. Тут ще може не бути складної рольової політики, але базова вимога вже є: спершу система має пов’язати запит із конкретним користувачем.

owner-only виникає майже миттєво, щойно в системі зʼявляються «мої об’єкти»: мої чернетки, мій профіль, мої налаштування, мої файли. І ось тут часто стається перше справжнє інженерне прозріння: роль USER сама по собі не розвʼязує задачу «це мій об’єкт чи чужий». Двоє користувачів можуть мати одну й ту саму роль і при цьому не мати права торкатися одних і тих самих даних.

editor і admin теж не є чимось екзотичним. Щойно в системі зʼявляються модерація, публікація, черга на перевірку або керування чужим контентом, у вас зʼявляється редакторський рівень привілеїв. Щойно зʼявляються ролі, блокування, увімкнення й вимкнення акаунтів, керування правами — ви вже в адміністративній зоні. Це не «enterprise-страшилки», а цілком звичайне життя бекенд-продукту.

Гарна новина: ця картина повторюється від проєкту до проєкту. Погана — якщо ви не навчилися помічати її рано, потім доводиться лікувати наслідки випадковими if-ами та коментарями на кшталт // TODO only admin.

4. Що видно на /api/me та /api/drafts/{id} 👤

Є два маршрути, на яких особливо зручно зловити різницю між схожими, але не рівними сценаріями.

@GetMapping("/api/me")
ProfileDto me() {
    return profileService.currentProfile();
}

@GetMapping("/api/drafts/{id}")
DraftDto one(@PathVariable long id) {
    return draftService.findById(id);
}

/api/me — це маршрут, привʼязаний до самого користувача. Уже сам шлях підказує: ідеться про поточного користувача. Тут немає довільного userId, який клієнт приносить із собою. Це вдалий дизайн для особистої зони, тому що він зменшує ризик випадково перетворити «мій профіль» на «будь-який профіль за id».

/api/drafts/{id} влаштований інакше. Тут клієнт обирає конкретний об’єкт за довільним ідентифікатором. І однієї аутентифікації тут уже замало. Недостатньо знати, що користувач взагалі існує. Потрібно ще перевірити, чи має він стосунок до цього об’єкта. Ось де й зʼявляється owner-only як окремий тип правила.

Цю різницю дуже корисно тримати в голові від самого початку. authenticated і owner-only звучать схоже, але інженерно це різні речі. У першому випадку достатньо сказати: «дія доступна відомому користувачеві». У другому потрібно ще й повʼязати користувача з об’єктом. Це вже не просто питання наявності ролі, а питання відношення між користувачем і даними.

5. Лінза з п’ятьма зонами для будь-якого API

Із усього, що вище, можна зібрати дуже практичний інструмент. Не теорію «про безпеку взагалі», а невелику лінзу, через яку корисно проганяти будь-який ендпоінт, навіть якщо ви поки зовсім не пишете Spring Security.

Питання до ендпоінту Якщо відповідь “так” Що це зазвичай означає
Чи може анонімний клієнт викликати цю дію? так public
Дія взагалі має сенс лише для відомого користувача? так принаймні authenticated
Клієнт обирає конкретний об’єкт за id або slug? так перевірте, чи не потрібен owner-only
Дія впливає на публікацію, модерацію або чужий контент? так подумайте про editor-рівень
Дія керує користувачами, ролями або системними налаштуваннями? так це вже admin

Ця таблиця навмисно проста. Вона не замінює майбутню конфігурацію і не враховує всі нюанси. Але як перший діагностичний фільтр працює чудово. Якщо ви проганяєте через неї свій API і майже всі ендпоінти раптом виявляються «ну, мабуть, authenticated», це майже завжди сигнал, що дизайн доступу ще не продуманий.

Саме такі маленькі діагностичні лінзи часто виявляються кориснішими за «повний глосарій на 50 термінів». Спочатку ви вчитеся розрізняти типи доступу, а вже потім обростаєте конкретною механікою. Для першого дня цього більш ніж достатньо 🙂

6. Де починається Spring Security

Якщо зовсім коротко: до цього моменту ви вчилися будувати бекенд, який відповідає на запити. Віднині ви вчитеся будувати бекенд, який усвідомлено обирає, кому і на яких умовах відповідати. У лінійці курсів це дуже природний наступний крок: спочатку Spring Boot і базовий REST, потім — шар доступу, якого раніше бракувало.

При цьому важливо відразу окреслити межі, щоб не було хибних очікувань. Цей курс не починається з OAuth2, зовнішніх identity-провайдерів і розподіленої security-архітектури. Спочатку ми наводимо лад усередині звичайного застосунку Spring Boot / Spring MVC. І це чесна послідовність: якщо ви не бачите public, authenticated, owner-only, editor, admin на простому домені, то просунуті теми перетворюються на набір модних слів без внутрішньої опори.

Поки достатньо тримати в голові одну думку: в одному компактному API вже живуть п’ять різних зон доступу. Отже, безпека в бекенді — це не «пізня позначка перед релізом», а частина архітектури від самого початку.

7. Типові помилки 🚧

Помилка №1: звести все до public і authenticated.
Так часто роблять із добрих намірів: хочеться швидко поділити API на «відкрите» і «закрите». Але щойно в системі є «мій об’єкт», модерація або адміністративні дії, таке грубе поділення починає брехати. Воно ховає реальні відмінності між сценаріями та робить небезпечні дії занадто схожими на звичайні.

Помилка №2: думати, що сам URL уже виражає правило доступу.
Маршрут /api/admin/** допомагає людині читати API, але не створює захист автоматично. Це адреса, а не перепустка. Поки правило не виражене явно, система не знає, що «admin» у шляху потрібно сприймати серйозно.

Помилка №3: плутати маршрути з прив’язкою до себе та сценарії owner-only.
/api/me і /api/drafts/{id} вимагають різного мислення. У першому випадку шлях уже жорстко привʼязаний до поточного користувача. У другому клієнт обирає об’єкт довільно, і там дуже швидко виникає перевірка «свій чи чужий».

Помилка №4: будувати розмову про доступ навколо ролей, а не навколо дій.
Роль корисна, але вона не повинна затіняти сам бізнес-зміст. Спочатку корисно проговорювати дію: «читати опубліковану статтю», «оновлювати свій профіль», «публікувати чернетку, надіслану на модерацію», «змінювати ролі користувачів». І лише потім підбирати рівень доступу під цю дію.

Коментарі
ЩОБ ПОДИВИТИСЯ ВСІ КОМЕНТАРІ АБО ЗАЛИШИТИ КОМЕНТАР,
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ