Как Spring Security выбирает кому дать доступ к данным
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
# Как Spring Security выбирает кому дать доступ к данным
Spring Security реализует многоуровневую систему контроля доступа, которая работает через сочетание аутентификации (проверка личности) и авторизации (проверка прав доступа).
Основные компоненты
1. AuthenticationManager
Первый уровень — аутентификация. AuthenticationManager проверяет учётные данные пользователя (логин/пароль, токен и т.д.) и создаёт объект Authentication.
@Bean
public AuthenticationManager authenticationManager(
UserDetailsService userDetailsService,
PasswordEncoder passwordEncoder) {
DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
provider.setUserDetailsService(userDetailsService);
provider.setPasswordEncoder(passwordEncoder);
return new ProviderManager(provider);
}
2. Authentication объект
После успешной аутентификации создаётся объект Authentication, содержащий:
- Principal (кто это — обычно UserDetails)
- Credentials (пароль, но обычно удаляется после аутентификации)
- Authorities (роли и права: ROLE_USER, ROLE_ADMIN и т.д.)
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
String username = auth.getName(); // получить имя
Collection<? extends GrantedAuthority> authorities = auth.getAuthorities();
3. SecurityContext
Authentication объект хранится в SecurityContext, который доступен во всей сессии:
SecurityContext context = SecurityContextHolder.getContext();
Authentication authentication = context.getAuthentication();
boolean isAuthenticated = authentication.isAuthenticated();
Авторизация — управление доступом
AccessDecisionManager
Это главный компонент, который решает, дать ли доступ к ресурсу. Есть три стратегии:
1. AffirmativeBased (по умолчанию) — доступ дан, если хотя бы один Voter проголосовал за:
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(auth -> auth
.requestMatchers("/admin/**").hasRole("ADMIN")
.requestMatchers("/user/**").hasRole("USER")
.requestMatchers("/public/**").permitAll()
.anyRequest().authenticated()
)
.formLogin();
return http.build();
}
}
2. UnanimousBased — доступ дан только если ВСЕ Voters проголосовали за:
http
.authorizeHttpRequests(auth -> auth
// Все проверки должны пройти
.requestMatchers("/critical/**").hasRole("ADMIN")
.requestMatchers("/critical/**").hasRole("VERIFIED")
);
3. ConsensusBased — доступ дан, если больше голосов за, чем против:
@Bean
public AccessDecisionManager consensusAccessDecisionManager() {
List<AccessDecisionVoter<?>> voters = new ArrayList<>();
voters.add(new RoleVoter());
voters.add(new WebExpressionVoter());
return new ConsensusBased(voters);
}
FilterSecurityInterceptor — точка принятия решения
У каждого URL определены требования доступа. Фильтр проверяет Authentication перед тем, как пропустить запрос:
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(auth -> auth
.requestMatchers("/admin/**").hasAnyRole("ADMIN", "SUPER_ADMIN")
.requestMatchers("/profile/**").authenticated()
.requestMatchers("/", "/login", "/register").permitAll()
.anyRequest().denyAll()
);
return http.build();
}
}
Типы проверок доступа
1. По ролям
.hasRole("ADMIN") // требует ROLE_ADMIN
.hasAnyRole("ADMIN", "MODERATOR")
2. По授权
.hasAuthority("DELETE_USER") // точное имя permission
.hasAnyAuthority("READ", "WRITE")
3. SpEL выражения
.access("hasRole('ADMIN') and #user.id == principal.id")
4. Кастомные проверки
@PostAuthorize("returnObject.owner.id == authentication.principal.id")
public Post getPost(Long id) {
return postRepository.findById(id);
}
Полный процесс проверки доступа
- Запрос приходит → FilterSecurityInterceptor перехватывает
- Получение Authentication → из SecurityContext
- Получение требований → какие роли нужны для этого URL
- Вызов AccessDecisionManager → сравнение Authentication с требованиями
- Voting → каждый Voter голосует (за/против/воздержался)
- Результат → доступ дан или AccessDeniedException
Пример с методами
@Service
public class UserService {
@PreAuthorize("hasRole('ADMIN')")
public void deleteUser(Long userId) {
// только ADMIN может удалить
}
@PreAuthorize("#userId == authentication.principal.id or hasRole('ADMIN')")
public User getUser(Long userId) {
// можешь получить свой профиль или ты админ
}
@PreAuthorize("hasAnyRole('ADMIN', 'MODERATOR')")
public void banUser(Long userId) {
// админ или модератор
}
}
Резюме
Spring Security даёт доступ на основе:
- Аутентификации (кто ты — проверка credentials)
- Authorities/Roles (какие у тебя права)
- ConfigAttributes (что требуется для ресурса)
- AccessDecisionManager (сравнение и голосование)
Этот многоуровневый подход позволяет реализовать гибкую и безопасную систему управления доступом.