
package com.example.jwtlogin.config;
import lombok.RequiredArgsConstructor;
import org.springframework.boot.autoconfigure.security.servlet.PathRequest;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.Customizer;
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.configuration.WebSecurityCustomizer;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.config.annotation.web.configurers.HeadersConfigurer;
import org.springframework.security.web.SecurityFilterChain;
@Configuration
@EnableWebSecurity
@EnableMethodSecurity
@RequiredArgsConstructor
public class SecurityConfig {
    @Bean
    public WebSecurityCustomizer webSecurityCustomizer() {
        return (web) ->
                web
                        .ignoring()
                        .requestMatchers("/main")
                        .requestMatchers(PathRequest.toStaticResources().atCommonLocations()
        );
    }
    @Bean
    protected SecurityFilterChain webSecurityFilterChain(HttpSecurity httpSecurity) throws Exception {
        httpSecurity
                .csrf(AbstractHttpConfigurer::disable)
                .formLogin(Customizer.withDefaults())
                .authorizeHttpRequests(
                        authorize -> authorize
                                .requestMatchers("/join", "/auth/login")
                                .permitAll()
                                .requestMatchers("/member/**")
                                .hasRole("MEMBER")
                )
                .headers(
                        httpSecurityHeadersConfigurer -> httpSecurityHeadersConfigurer
                                .frameOptions(
                                        HeadersConfigurer.FrameOptionsConfig::sameOrigin
                                )
                );
        return httpSecurity.build();
    }
}
PathRequest.toStaticResources().atCommonLocations()StaticResourceLocation Enum을 반환한다. 
📝 ignore() vs permitAll()
ignore()은 필터를 거치지 않고,permitAll()은 필터를 거친다.CSRF,XSS,Clickjacking등의 취약점으로부터 보호하기 위해서는HttpSecurity에서permitAll()을 하는 것이 권장된다.
HttpSecurity 구성 시, SecurityFilterChain을 @Bean 등록하도록 권장되고 있다. authorizeHttpRequests(): 특정 리소스에 대한 접근권한을 설정한다.Customizer.withDefaults(): 기본 옵션으로 사용하려는 매개변수에 사용한다.
Spring Boot 3.x.x버전 즉,Security 6.1.x버전 부터는 기존에 썼던csrf(),formLogin(),headers()와 같이 인수를 갖지 않는 메서드들은 전부 Deprecated 되었다.
CSRF protection은 spring security에서 default로 설정된다.GET요청을 제외한 상태를 변화시킬 수 있는 POST, PUT, DELETE 요청으로부터 보호한다.<input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}"/>
📝 CSRF 공격이란?
- 웹 어플리케이션 취약점 중 하나로 인터넷 사용자가 자신의 의지와는 무관하게 공격자가 의도한 행위(수정, 삭제, 등록 등)를 특정 웹사이트에 요청하게 만드는 공격
 - XSS는 사용자(희생자)의 PC에서 스크립트가 실행되지만, CSRF는 서버에서 스크립트가 실행된다.
 
httpSecurity.csrf(AbstractHttpConfigurer::disable)
rest api를 이용한 서버라면, session 기반 인증과는 다르게 stateless하기 때문에 서버에 인증정보를 보관하지 않는다. rest api에서 클라이언트는 권한이 필요한 요청을 하기 위해서는 요청에 필요한 인증 정보를(OAuth2, jwt token 등)을 포함시켜야 한다.💡 서버에 인증정보를 저장하지 않으므로, CSRF protection을 굳이 사용할 이유가 없다.
출처
  스프링 시큐리티 (Spring Security)
최신 Spring Security 사용법 - SecurityFilterChain
[Spring Boot] Spring Boot 3.x SecurityConfig 설정하기
Spring Boot 3.x + Security 6.x 기본 설정 및 변화
[스프링시큐리티] Spring Security 5.7 (WebSecurityConfigurerAdapter 에러해결방법)
[Spring Security] 정적 자원 ignore하기
[Spring]Spring security - CSRF란?, http.csrf().disable() ?
[spring] spring security를 이용한 JWT 로그인