Привет, это снова Егор Гаврилов. Сегодня я расскажу, что было сделано за последний месяц в рамках очередного своего пет-проекта - StingrayTV Alice.

Предыдущая статья была вынесена в черновики мной, однако если вкратце, StingrayTV Alice - это попытка интегрировать ресиверы Триколора на базе платформы StingrayTV с сервисом "Дом с Алисой". Это позволяет управлять ресивером через Алису, и интегрировать его в общий умный дом. Проект пережил несколько доработок, и сейчас там используется Keycloak, Spring Boot 4, и другие самые современные технологии. Также было сделано множество улучшений кодовой базы, что позволило избавиться от лишнего кода, и улучшить стабильность и производительность данного гейтвея.

Keycloak: теперь нормальная аутентификация - это реальность

Изначально планировалась аутентификация по физическому присутствию пользователя за консолью сервера. Однако реализовать это достаточно было нетривиально, и поэтому принято решение использовать уже готовый сервер аутентификации - а именно Keycloak. Оно даёт более гибкий контроль за процессом аутентификации, а также является проверенным и готовым решением для реализации OAuth2.

Мы его реализовали на базе Spring OAuth2 Resource Server. Для этого достаточно одного конфигурационного класса, и одного параметра в application.yml

/**
 * Security configuration for Keycloak authentication.
 */
@Configuration
@EnableWebSecurity
@Slf4j
public class SecurityConfig {

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) {
        http
                .csrf(AbstractHttpConfigurer::disable)
                .sessionManagement(session -> session
                        .sessionCreationPolicy(SessionCreationPolicy.STATELESS))
                .authorizeHttpRequests(auth -> auth
                        .requestMatchers("/v1.0").permitAll()
                        .anyRequest().authenticated()
                )
                .oauth2ResourceServer(oauth2 -> oauth2.jwt(
                        jwt -> jwt.jwtAuthenticationConverter(new KeycloakConverter())
                ))
                .exceptionHandling(exception -> exception
                        .authenticationEntryPoint((request, response, authException) -> {
                            log.warn("Authentication failed for request: {} {}",
                                    request.getMethod(), request.getRequestURI());
                            response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
                            response.setContentType("application/json");
                            response.getWriter().write("{\"error\":\"Unauthorized\",\"message\":\"Authentication required\"}");
                        })
                        .accessDeniedHandler((request, response, accessDeniedException) -> {
                            log.warn("Access denied for request: {} {}",
                                    request.getMethod(), request.getRequestURI());
                            response.setStatus(HttpServletResponse.SC_FORBIDDEN);
                            response.setContentType("application/json");
                            response.getWriter().write("{\"error\":\"Forbidden\",\"message\":\"Access denied\"}");
                        })
                )
                .cors(Customizer.withDefaults());

        return http.build();
    }
}
spring:
  security:
    oauth2:
      resourceserver:
        jwt:
          issuer-uri: ${KEYCLOAK_ISSUER_URI:http://keycloak:8080/auth/realms/stingray}

Куча рефакторинга

Проект подвергся обширному рефакторингу - как те, которые я сделал на всех своих пет-проектах (в частности, перевод проектов на Spring Boot 4, а также улучшения по части CI/CD в проектах - теперь там реализован полноценный пайплайн, который обеспечивает высокий уровень консистентности всего цикла), так и постепенная работа над чисткой кода (при помощи самых разных линтинг-инструментов - начиная от встроенных инструментов OpenIDE, и заканчивая SonarQube for IDE и Explyt Spring). Это позволило обеспечить гораздо большую чистоту и сопровождаемость кода.

В частности:

  1. Избавились от кривого механизма аутентификации - теперь там самый что ни на есть цивильный Keycloak.

  2. Убрали использование Preferences API для хранения нужных ключей для старого механизма аутентификации - Keycloak куда лучше во всём.

  3. Мелкие улучшения в кодовой базе - меньше ужаса и треша, больше чистого кода.

Итоги

Проект пережил многое - но теперь оно всё ближе к тому, чтобы можно было использовать у себя дома, безопасно и спокойно.

Мой сайт-резюме
Мой GitHub

Комментарии (0)