Ответ
Кастомизация в Spring Security обычно реализуется через расширение ключевых компонентов.
1. Кастомная аутентификация (например, по JWT):
- Создайте фильтр для извлечения и валидации токена.
- Реализуйте
AuthenticationProviderили используйте стандартный, установив кастомныйUserDetailsService.
@Service
public class CustomUserDetailsService implements UserDetailsService {
@Override
public UserDetails loadUserByUsername(String username) {
// Ваша логика загрузки пользователя из БД или другого источника
User user = userRepository.findByUsername(username);
if (user == null) {
throw new UsernameNotFoundException("User not found");
}
// Преобразование ролей/прав в GrantedAuthority
List<GrantedAuthority> authorities = user.getRoles().stream()
.map(role -> new SimpleGrantedAuthority("ROLE_" + role.getName()))
.collect(Collectors.toList());
return new org.springframework.security.core.userdetails.User(
user.getUsername(),
user.getPassword(),
authorities
);
}
}
2. Кастомная конфигурация доступа: Настройте SecurityFilterChain, чтобы определить правила для разных эндпоинтов и подключить свои фильтры.
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(authz -> authz
.requestMatchers("/api/admin/**").hasRole("ADMIN")
.requestMatchers("/api/user/**").hasAnyRole("USER", "ADMIN")
.requestMatchers("/public/**").permitAll()
.anyRequest().authenticated()
)
// Добавление кастомного JWT-фильтра перед стандартным
.addFilterBefore(new JwtAuthenticationFilter(),
UsernamePasswordAuthenticationFilter.class)
.csrf(csrf -> csrf.disable()) // Отключаем для stateless API
.sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS));
return http.build();
}
3. Кастомная логика авторизации: Для сложных правил (например, на основе атрибутов объекта) реализуйте @PreAuthorize с SpEL или создайте собственный PermissionEvaluator.
Ответ 18+ 🔞
А, ну вот, опять эти ваши кастомные штуки в Spring Security. Слушай, а как же без них, блядь? Без кастомизации там нихуя не работает, как надо. Все эти стандартные формы логина — они ж для школьных проектов, а в реальной жизни нужно всё под себя запиливать, иначе писец.
Так, смотри, первое, что обычно всем нужно — это своя аутентификация. Ну, например, по JWT, который сейчас у всех в рот засунут. Что делаем? Правильно, пишем свой фильтр, который этот токен из запроса выковыривает, проверяет, не просрочился ли, не подделан ли. А потом, блядь, нужно как-то сказать Спрингу: «Смотри, чувак, вот пользователь, вот его роли, считай его своим».
Для этого либо свой AuthenticationProvider городишь, либо, что проще — используешь стандартный, но подсовываешь ему свой UserDetailsService. Вот смотри, как это выглядит, если не выёбываться:
@Service
public class CustomUserDetailsService implements UserDetailsService {
@Override
public UserDetails loadUserByUsername(String username) {
// Твоя логика, где ты лезешь в базу или куда-то ещё за пользователем
User user = userRepository.findByUsername(username);
if (user == null) {
throw new UsernameNotFoundException("User not found");
}
// Превращаешь его роли в эти ваши GrantedAuthority
List<GrantedAuthority> authorities = user.getRoles().stream()
.map(role -> new SimpleGrantedAuthority("ROLE_" + role.getName()))
.collect(Collectors.toList());
// И возвращаешь обёртку, которую Спринг уже понимает
return new org.springframework.security.core.userdetails.User(
user.getUsername(),
user.getPassword(),
authorities
);
}
}
Всё, блядь. Теперь твой сервис знает, где брать юзеров. Но это полдела.
Дальше — конфигурация доступа. Это где ты говоришь, кому куда можно ходить. Тут уже в SecurityFilterChain всё описываешь. И, что самое главное, свой JWT-фильтр туда впихиваешь, чтобы он работал до стандартной аутентификации по логину-паролю.
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(authz -> authz
.requestMatchers("/api/admin/**").hasRole("ADMIN") // Сюда только админы
.requestMatchers("/api/user/**").hasAnyRole("USER", "ADMIN") // Сюда юзеры и админы
.requestMatchers("/public/**").permitAll() // А сюда вообще все, кто угодно
.anyRequest().authenticated() // Всё остальное — только для авторизованных
)
// Вот тут магия! Подсовываем свой фильтр перед стандартным
.addFilterBefore(new JwtAuthenticationFilter(),
UsernamePasswordAuthenticationFilter.class)
.csrf(csrf -> csrf.disable()) // Для API обычно выключаем, иначе мозг сломаешь
.sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS)); // Без сессий, stateless же
return http.build();
}
Ну и третий пункт — это когда простых ролей уже не хватает. Ну там, «пользователь может редактировать только СВОЮ статью», а не все подряд. Вот тут уже начинается цирк с @PreAuthorize и SpEL выражениями. А если совсем пиздец сложная логика, то пишешь свой PermissionEvaluator — это такая штука, которая решает, можно ли юзеру делать что-то с конкретным объектом. Но это, блядь, уже для гурманов, когда простые методы не катят.
Короче, суть в чём: Spring Security — он как конструктор. Детали стандартные есть, но если хочешь что-то своё — бери и переопределяй. Главное, не накосячить в цепочке фильтров, а то будет «доступ запрещён» там, где не надо, и наоборот.