content: package com.seasonthon.everflow.app.global.security;
  
  import com.seasonthon.everflow.app.user.repository.UserRepository;
  import lombok.RequiredArgsConstructor;
  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.annotation.web.configurers.AbstractHttpConfigurer;
  import org.springframework.security.config.http.SessionCreationPolicy;
  import org.springframework.security.crypto.factory.PasswordEncoderFactories;
  import org.springframework.security.crypto.password.PasswordEncoder;
  import org.springframework.security.web.SecurityFilterChain;
  import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
  import org.springframework.web.cors.CorsConfiguration;
  import org.springframework.web.cors.CorsConfigurationSource;
  import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
  import java.util.Arrays;
  
  @Configuration
  @EnableWebSecurity
  @RequiredArgsConstructor
  public class SecurityConfig {
  
      private final JwtService jwtService;
      private final UserRepository userRepository;
      private final TokenBlacklistService tokenBlacklistService;
      private final JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint;
  
      @Bean
      public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
          http
                  .csrf(AbstractHttpConfigurer::disable)
                  .cors(cors -> cors.configurationSource(corsConfigurationSource()))
                  .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
                  .exceptionHandling(exception -> exception
                          .authenticationEntryPoint(jwtAuthenticationEntryPoint)
                          .accessDeniedHandler(jwtAuthenticationEntryPoint)
                  )
                  .authorizeHttpRequests(auth -> auth
                          // 소셜 로그인 관련 경로는 모두 허용
                          .requestMatchers("/auth/**", "/api/v1/auth/**").permitAll()
                          // Swagger 문서 경로는 모두 허용
                          .requestMatchers("/swagger-ui.html", "/swagger-ui/**", "/v3/api-docs/**").permitAll()
                          .requestMatchers("/family/verify/**").permitAll()
                          .requestMatchers("/api/notifications/**").permitAll()
                          .anyRequest().authenticated()
                  )
                  // JWT 인증 필터를 UsernamePasswordAuthenticationFilter 이전에 추가
                  .addFilterBefore(jwtAuthenticationProcessingFilter(), UsernamePasswordAuthenticationFilter.class);
  
          return http.build();
      }
  
      @Bean
      public CorsConfigurationSource corsConfigurationSource() {
          CorsConfiguration configuration = new CorsConfiguration();
          configuration.setAllowedOrigins(Arrays.asList(
                  "http://localhost:3000",
                  "http://localhost:5173",
                  "https://everflowfront.vercel.app"
          ));
          configuration.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS"));
          configuration.setAllowedHeaders(Arrays.asList("Authorization", "RefreshToken", "id_token", "Content-Type"));
          configuration.setExposedHeaders(Arrays.asList("Authorization", "RefreshToken"));
          configuration.setAllowCredentials(true);
  
          UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
          source.registerCorsConfiguration("/**", configuration);
          return source;
      }
  
      @Bean
      public JwtAuthenticationProcessingFilter jwtAuthenticationProcessingFilter() {
          return new JwtAuthenticationProcessingFilter(jwtService, userRepository, tokenBlacklistService);
      }
  
      @Bean
      public PasswordEncoder passwordEncoder() {
          return PasswordEncoderFactories.createDelegatingPasswordEncoder();
      }
  }
  