@Slf4j
@Configuration
public class SecurityConfig {
/**
* 이 메서드는 정적 자원에 대해 보안을 적용하지 않도록 설정한다.
* 정적 자원은 보통 HTML, CSS, JavaScript, 이미지 파일 등을 의미하며, 이들에 대해 보안을 적용하지 않음으로써 성능을 향상시킬 수 있다.
*/
@Bean
public WebSecurityCustomizer webSecurityCustomizer() {
return web -> web.ignoring()
.requestMatchers(PathRequest.toStaticResources().atCommonLocations());
}
@Bean
public CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(Arrays.asList("*"));
configuration.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "DELETE"));
configuration.setAllowedHeaders(Arrays.asList("X-Requested-With", "Content-Type", "Authorization", "X-XSRF-token"));
configuration.setAllowCredentials(false);
configuration.setMaxAge(3600L);
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
/**
* Spring Security 설정을 정의하는 메서드.
* <ul>
* <li>CSRF 방지 기능 비활성화</li>
* <li>CORS 설정 적용</li>
* <li>`/resources/**`, `/main/rootPage` 경로 접근 허용</li>
* <li>나머지 요청은 인증된 사용자만 접근 허용</li>
* <li>헤더의 JWT 토큰을 추출하고 검증하는 `JwtAuthorizationFilter` 적용</li>
* <li>세션을 상태 없이 관리</li>
* <li>로그인 페이지 설정 및 로그인 성공 시 리다이렉트 경로 설정</li>
* <li>사용자 이름과 비밀번호 인증을 위한 `CustomAuthenticationFilter` 적용</li>
* </ul>
*
* @param http Spring Security의 HttpSecurity 객체
* @param customAuthenticationFilter 사용자 정의 인증 필터
* @param jwtAuthorizationFilter JWT 인증 필터
* @return 구성된 SecurityFilterChain 객체
* @throws Exception 설정 중 발생할 수 있는 예외
*/
@Bean
public SecurityFilterChain filterChain(
HttpSecurity http,
CustomAuthenticationFilter customAuthenticationFilter,
JwtAuthorizationFilter jwtAuthorizationFilter
) throws Exception {
log.debug("[+] WebSecurityConfig Start !!! ");
return http
.csrf(AbstractHttpConfigurer::disable)
.cors(cors -> cors.configurationSource(corsConfigurationSource()))
.authorizeHttpRequests(authorize -> authorize
.requestMatchers("/resources/**", "/static/**").permitAll()
.requestMatchers("/css/**").permitAll()
.requestMatchers("/main/rootPage").permitAll()
.requestMatchers("/error.html").permitAll()
.anyRequest().authenticated()
)
.addFilterBefore(jwtAuthorizationFilter, BasicAuthenticationFilter.class)
.sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
.formLogin(login -> login
.loginPage("/login")
.successHandler(new SimpleUrlAuthenticationSuccessHandler("/main/rootPage"))
.permitAll()
)
.addFilterBefore(customAuthenticationFilter, UsernamePasswordAuthenticationFilter.class)
.build();
}
/**
* 1. 커스텀을 수행한 '인증' 필터로 접근 URL, 데이터 전달방식(form) 등 인증 과정 및 인증 후 처리에 대한 설정을 구성하는 메서드다.
* 이 메서드는 사용자 정의 인증 필터를 생성한다. 이 필터는 로그인 요청을 처리하고, 인증 성공/실패 핸들러를 설정한다.
*
* @return CustomAuthenticationFilter
*/
@Bean
public CustomAuthenticationFilter customAuthenticationFilter(
AuthenticationManager authenticationManager,
CustomAuthSuccessHandler customAuthSuccessHandler,
CustomAuthFailureHandler customAuthFailureHandler
) {
CustomAuthenticationFilter customAuthenticationFilter = new CustomAuthenticationFilter(authenticationManager);
// "/user/login" 엔드포인트로 들어오는 요청을 CustomAuthenticationFilter에서 처리하도록 지정한다.
customAuthenticationFilter.setFilterProcessesUrl("/user/login");
customAuthenticationFilter.setAuthenticationSuccessHandler(customAuthSuccessHandler); // '인증' 성공 시 해당 핸들러로 처리를 전가한다.
customAuthenticationFilter.setAuthenticationFailureHandler(customAuthFailureHandler); // '인증' 실패 시 해당 핸들러로 처리를 전가한다.
customAuthenticationFilter.afterPropertiesSet();
return customAuthenticationFilter;
}
/**
* 2. authenticate 의 인증 메서드를 제공하는 매니져로'Provider'의 인터페이스를 의미한다.
* 이 메서드는 인증 매니저를 생성한다. 인증 매니저는 인증 과정을 처리하는 역할을 한다.
* 과정: CustomAuthenticationFilter → AuthenticationManager(interface) → CustomAuthenticationProvider(implements)
*/
@Bean
public AuthenticationManager authenticationManager(CustomAuthenticationProvider customAuthenticationProvider) {
return new ProviderManager(Collections.singletonList(customAuthenticationProvider));
}
/**
* 3. '인증' 제공자로 사용자의 이름과 비밀번호가 요구된다.
* 이 메서드는 사용자 정의 인증 제공자를 생성한다. 인증 제공자는 사용자 이름과 비밀번호를 사용하여 인증을 수행한다.
* 과정: CustomAuthenticationFilter → AuthenticationManager(interface) → CustomAuthenticationProvider(implements)
*/
@Bean
public CustomAuthenticationProvider customAuthenticationProvider(UserDetailsService userDetailsService) {
return new CustomAuthenticationProvider(
userDetailsService
);
}
/**
* 4. Spring Security 기반의 사용자의 정보가 맞을 경우 수행이 되며 결과값을 리턴해주는 Handler
* customLoginSuccessHandler: 이 메서드는 인증 성공 핸들러를 생성한다. 인증 성공 핸들러는 인증 성공시 수행할 작업을 정의한다.
*/
@Bean
public CustomAuthSuccessHandler customLoginSuccessHandler() {
return new CustomAuthSuccessHandler();
}
/**
* 5. Spring Security 기반의 사용자의 정보가 맞지 않을 경우 수행이 되며 결과값을 리턴해주는 Handler
* customLoginFailureHandler: 이 메서드는 인증 실패 핸들러를 생성한다. 인증 실패 핸들러는 인증 실패시 수행할 작업을 정의한다.
*/
@Bean
public CustomAuthFailureHandler customLoginFailureHandler() {
return new CustomAuthFailureHandler();
}
/**
* "JWT 토큰을 통하여서 사용자를 인증한다." -> 이 메서드는 JWT 인증 필터를 생성한다.
* JWT 인증 필터는 요청 헤더의 JWT 토큰을 검증하고, 토큰이 유효하면 토큰에서 사용자의 정보와 권한을 추출하여 SecurityContext에 저장한다.
*/
@Bean
public JwtAuthorizationFilter jwtAuthorizationFilter(CustomUserDetailsService userDetailsService) {
return new JwtAuthorizationFilter(userDetailsService);
}
/**
* isAdmin 메소드는 Supplier<Authentication>와 RequestAuthorizationContext를 인자로 받아서 "ADMIN" 역할을 가진 사용자인지 확인한다.
* 만약 사용자가 "ADMIN" 역할을 가지고 있다면, AuthorizationDecision 객체는 true를 반환하고, 그렇지 않다면 false를 반환한다.
*/
private AuthorizationDecision isAdmin(
Supplier<Authentication> authenticationSupplier,
RequestAuthorizationContext requestAuthorizationContext
) {
return new AuthorizationDecision(
authenticationSupplier.get()
.getAuthorities()
.contains(new SimpleGrantedAuthority("ADMIN"))
);
}
}
'2024 웹 > Spring & Spring Boot' 카테고리의 다른 글
aws 배포 자료 (2) | 2024.06.08 |
---|---|
도커 배포 참고자료 (0) | 2024.05.02 |
spring dependency (0) | 2024.04.29 |
Spring AOP(Aspect Oriented Programming) (0) | 2024.04.18 |
JdbcTemplate and BeanPropertyRowMapper 사용 (0) | 2024.04.16 |
댓글