SecurityConfig.java
package com.newbit.common.config;
import com.newbit.auth.jwt.RestAccessDeniedHandler;
import com.newbit.auth.jwt.RestAuthenticationEntryPoint;
import com.newbit.auth.jwt.JwtTokenProvider;
import com.newbit.auth.jwt.JwtAuthenticationFilter;
import jakarta.servlet.Filter;
import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
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.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
@Configuration
@EnableWebSecurity
@EnableMethodSecurity(prePostEnabled = true) // @PreAuthorize, @PostAuthorize 사용을 위해
@RequiredArgsConstructor
public class SecurityConfig {
private final JwtTokenProvider jwtTokenProvider;
private final UserDetailsService userDetailsService;
private final RestAuthenticationEntryPoint restAuthenticationEntryPoint;
private final RestAccessDeniedHandler restAccessDeniedHandler;
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
public UserDetailsService userDetailsService(PasswordEncoder passwordEncoder) {
UserDetails user = User.builder()
.username("admin")
.password(passwordEncoder.encode("admin1234"))
.roles("ADMIN")
.build();
return new InMemoryUserDetailsManager(user);
}
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
// CSRF 처리 비활성화 (default 가 활성화이므로 작성해주어야 한다)
http.csrf(AbstractHttpConfigurer::disable)
// 세션 로그인 x -> 토큰 로그인 설정으로 진행한다
.sessionManagement(session
-> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
// 인증 실패, 인가 실패 핸들러
.exceptionHandling(exception ->
exception
.authenticationEntryPoint(restAuthenticationEntryPoint) // 인증 실패
.accessDeniedHandler(restAccessDeniedHandler) // 인가 실패
)
// 요청 http method, url 기준으로 인증, 인가 필요 여부 설정
.authorizeHttpRequests(auth ->
auth.anyRequest().permitAll()
)
// 커스텀 인증 필터(JWT 토큰 사용하여 확인)를 인증 필터 앞에 삽입
.addFilterBefore(jwtAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
return http.build();
}
@Bean
public Filter jwtAuthenticationFilter() {
return new JwtAuthenticationFilter(jwtTokenProvider, userDetailsService);
}
}