Spring Security basics
Цель урока
Сделать полноценный CRUD для задач с правильными HTTP-статусами (201/204/404), обработкой ошибок, и подготовить Task к подключению JPA.
Теория · для собеса
1 Архитектура Spring Security ▸
Основа — цепочка фильтров (Filter Chain). Каждый HTTP-запрос проходит через ~15 фильтров ДО Controller'а:
HTTP request
↓
[SecurityContextHolderFilter] ← создаёт SecurityContext
↓
[CsrfFilter] ← проверяет CSRF-токен
↓
[UsernamePasswordAuthenticationFilter] ← логин по form
↓
[BearerTokenAuthenticationFilter] ← JWT (если есть)
↓
[AuthorizationFilter] ← проверяет @PreAuthorize, hasRole
↓
[Controller]
2 Ключевые понятия ▸
- Authentication (кто ты?) — Principal (юзер), Credentials (пароль/токен), Authorities (роли)
- Authorization (что тебе можно?) — проверка прав на действие
- SecurityContext — хранит
Authenticationдля текущего запроса (черезThreadLocal) - UserDetails — Spring-интерфейс для юзера (имя, пароль, authorities)
- UserDetailsService — загрузка юзера по имени
- PasswordEncoder — хеширование пароля (BCrypt)
3 Что нового в Spring Security 6 ▸
- ❌ Удалён
WebSecurityConfigurerAdapter(deprecated с 5.7) - ✅ Вместо него —
SecurityFilterChainбин - ✅ Конфигурация через лямбды (функциональный стиль)
- ✅ Встроенный
AuthenticationProviderдля OAuth 2 / JWT
---
Практика: улучшаем CRUD
-
1Зависимости
dependencies { implementation("org.springframework.boot:spring-boot-starter-security") } -
2
config/SecurityConfig.java(новый стиль)package com.taskflow.config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.http.SessionCreationPolicy; import org.springframework.security.core.userdetails.User; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.provisioning.InMemoryUserDetailsManager; import org.springframework.security.web.SecurityFilterChain; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; @Configuration @EnableWebSecurity public class SecurityConfig { @Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http // Отключаем CSRF — мы используем JWT (stateless), не cookies+forms .csrf(csrf -> csrf.disable()) // Настройка прав .authorizeHttpRequests(auth -> auth // Public endpoints .requestMatchers("/api/auth/**", "/api/health", "/v3/api-docs/**", "/swagger-ui/**").permitAll() // Admin only .requestMatchers("/api/admin/**").hasRole("ADMIN") // Остальные — только аутентифицированные .anyRequest().authenticated() ) // Stateless — не создаём HTTP-сессию .sessionManagement(s -> s.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) // Basic Auth — для теста (в уроке 12 заменим на JWT) .httpBasic(b -> {}) // Form login — отключаем .formLogin(f -> f.disable()) // Logout — настраиваем .logout(l -> l .logoutUrl("/api/auth/logout") .logoutSuccessHandler((req, res, auth) -> res.setStatus(200)) ); return http.build(); } // Пока — in-memory юзер, в уроке 11 заменим на JPA @Bean public UserDetailsService userDetailsService(PasswordEncoder encoder) { UserDetails user = User.builder() .username("alice") .password(encoder.encode("password123")) .roles("USER") .build(); UserDetails admin = User.builder() .username("admin") .password(encoder.encode("admin123")) .roles("USER", "ADMIN") .build(); return new InMemoryUserDetailsManager(user, admin); } @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(12); } } -
3Тест: запускаем и проверяем
./gradlew bootRun# Public endpoint — без авторизации $ curl http://localhost:8080/api/health {"status":"UP","version":"0.1.0","timestamp":"2026-06-29T16:40:00Z"} # Защищённый endpoint — 401 без токена $ curl -i http://localhost:8080/api/tasks HTTP/1.1 401 # С Basic Auth — работает $ curl -u alice:password123 http://localhost:8080/api/tasks [] # Admin endpoint — 403 для USER $ curl -u alice:password123 http://localhost:8080/api/admin/dashboard HTTP/1.1 403 # Admin endpoint — 200 для ADMIN $ curl -u admin:admin123 http://localhost:8080/api/admin/dashboard {"adminsOnly":true} -
4Логирование в Spring Security (для дебага)
application-dev.yml:logging: level: org.springframework.security: DEBUG org.springframework.security.web.FilterChainProxy: TRACE---
Зачем это на собесе
После урока ты должен уметь ответить на:
strength=12 — баланс между скоростью и безопасностью (2^12 = 4096 итераций).5 вопросов на углубление
Раскрой вопрос и нажми «🤔 Хочу разобрать подробнее» — он попадёт в страницу ответов.
Разбор внутри: дефолтный user, basic/form login и почему нужен свой SecurityFilterChain.
Разбор внутри: log2 rounds, цена хеширования и баланс скорости/безопасности.
Разбор внутри: JWT в Authorization header против cookie-based login.
Разбор внутри: ROLE_ prefix, роли, permissions и scopes.
Разбор внутри: REST/JWT и классическое web-приложение с сессией.
Готов идти дальше?
Выбери вопросы, которые тебе интересны, и изучи их. Потом — к следующему уроку.
🚀 Перейти к Уроку 11Сначала пройди все секции и выбери хотя бы 1 вопрос
⬅️ Назад к Уроку 9