Аутентификация и авторизация в Spring Security
Аутентификация — процесс проверки личности пользователя (кто он).
Авторизация — проверка прав доступа (что он может делать).
В Spring Security аутентификация строится на основе
интерфейсов UserDetails, UserDetailsService и AuthenticationProvider.
Основные этапы:
Пользователь вводит логин и пароль.
SecurityFilterChain передает запрос в AuthenticationProvider.
Провайдер сверяет данные с базой и создает объект Authentication.
Информация сохраняется в SecurityContext.
При последующих запросах права проверяются автоматически.
Подробное объяснение
Чтобы понять, как Spring Security обрабатывает пользователей, важно разделить два понятия:
— аутентификация отвечает на вопрос «кто этот человек?»,
— авторизация — «имеет ли он право выполнить это действие?».
1. Ключевые интерфейсы
UserDetails
Описывает пользователя: имя, пароль и роли.
public class MyUserDetails implements UserDetails {
private final User user;
public MyUserDetails(User user) { this.user = user; }
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return List.of(new SimpleGrantedAuthority("ROLE_" + user.getRole()));
}
@Override
public String getPassword() { return user.getPassword(); }
@Override
public String getUsername() { return user.getUsername(); }
@Override
public boolean isAccountNonExpired() { return true; }
@Override
public boolean isAccountNonLocked() { return true; }
@Override
public boolean isCredentialsNonExpired() { return true; }
@Override
public boolean isEnabled() { return true; }
}
Spring Security всегда оперирует объектами UserDetails, даже если вы храните пользователей в собственной таблице.
UserDetailsService
Сервис, который по имени пользователя загружает его данные из источника (например, из базы).
@Service
public class MyUserDetailsService implements UserDetailsService {
private final UserRepository repository;
public MyUserDetailsService(UserRepository repository) {
this.repository = repository;
}
@Override
public UserDetails loadUserByUsername(String username)
throws UsernameNotFoundException {
return repository.findByUsername(username)
.map(MyUserDetails::new)
.orElseThrow(() ->
new UsernameNotFoundException("Пользователь не найден"));
}
}
Когда пользователь пытается войти, Spring вызывает этот сервис, получает UserDetails и сравнивает пароль с введенным.
2. Настройка аутентификации
В конфигурации Spring Security нужно указать, как система будет проверять пользователей.
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
return http
.authorizeHttpRequests(auth -> auth
.requestMatchers("/login", "/register").permitAll()
.anyRequest().authenticated())
.formLogin(Customizer.withDefaults())
.build();
}
@Bean
public UserDetailsService userDetailsService(UserRepository repository) {
return new MyUserDetailsService(repository);
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
Обратите внимание:
formLogin() включает стандартную страницу входа;
PasswordEncoder обязателен — Spring не позволит хранить пароль в открытом виде;
BCryptPasswordEncoder — безопасный алгоритм хеширования паролей, рекомендуемый по умолчанию.
3. Создание пользователя в памяти (для теста)
Для учебных примеров можно не подключать базу, а создать пользователя прямо в конфигурации:
@Bean
public UserDetailsService users() {
UserDetails user = User.builder()
.username("admin")
.password(passwordEncoder().encode("1234"))
.roles("ADMIN")
.build();
return new InMemoryUserDetailsManager(user);
}
Теперь можно войти в приложение с логином admin и паролем 1234.
4. Авторизация по ролям и аннотации
После успешной аутентификации система знает, какие роли у пользователя.
Для ограничения доступа к методам используются аннотации:
@PreAuthorize("hasRole('ADMIN')")
public void deleteUser(Long id) { ... }
@PreAuthorize("hasAnyRole('MANAGER', 'ADMIN')")
public void viewReport() { ... }
Spring проверит роли перед выполнением метода и вернет 403 Forbidden,
если у пользователя нет соответствующих прав.
Чтобы эти аннотации работали, нужно включить их в конфигурации:
@EnableMethodSecurity
public class SecurityConfig { ... }
5. Хранение состояния пользователя
После успешного входа информация о пользователе хранится в SecurityContext.
Этот контекст доступен в любом месте программы:
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
String username = auth.getName();
System.out.println("Текущий пользователь: " + username);
Таким образом, можно определить, кто выполняет действие, и применять логику в зависимости от роли.
Итог:
Аутентификация и авторизация в Spring Security разделены, но работают вместе.
UserDetailsService отвечает за загрузку данных пользователя,
AuthenticationManager и PasswordEncoder — за проверку подлинности,
а аннотации @PreAuthorize и @Secured обеспечивают контроль доступа на уровне методов.
