생각
spring security에 대해서 수업을 듣다가 사용자 권한에 들어가면서 특정 클래스에 @Configuration 어노테이션을 정의해줬다. 그래서 이게 정확히 무엇인지 궁금했다.
그리고 찾아보니 @Bean과 같이 사용되는데 각 Bean의 인스턴스는 컨테이너 내에서 하나만 존재 한다는 설명을 듣고 이해가 안 갔다. 하나만 존재한다는 말이 무슨 말인지 이해가 가지 않아서 관련 내용을 더 찾아보았다.
@Configuration, @Bean,
@EnableWebSecurity,
SecurityFilterChain, HttpSecurity의 중요성
- Spring Security에서 보안 관련 기능을 추가하려면 SecurityFilterChain 인터페이스를 사용해야한다.
- 그리고 SecurityFilterChain 인터페이스를 사용하기 위해서는 @Configuration과 @EnableWebSecurity 어노테이션을 사용하여 보안 설정 클래스를 만들어야한다. 그래야지 필터 체인을 정의하고 필요한 보안 설정을 추가할 수 있다.
@Configuration
- Java 기반의 설정 클래스를 정의하는 데 사용된다.
- 이 어노테이션이 붙은 클래스는 Spring의 애플리케이션 컨텍스트에서 Bean을 정의하고 설정할 수 있다.
- @Configuration이 붙은 클래스 안에는 @Bean 어노테이션이 붙은 메소드가 있을 수 있다. 이메소드들은 Spring 컨테이너에 의해 관리되는 Bean을 정의한다.
- Bean을 수동으로 등록하기 위해서 사용한다.
- Bean을 등록할 때 싱글톤(singleton)이 되도록 보장해준다.
- SecurityFilterChain 인터페이스 타입의 클래스를 생성할 때 @Configuration을 설정하면 스프링 설정 파일처럼 동작하게 만든다.
@Bean
- 주로 객체를 생성하고 스프링 컨테이너에 등록하여, 애플리케이션 전반에서 쉽게 사용할 수 있도록 할 때 사용된다. 또한 의존성을 관리하고, 초기화 및 소멸 로직을 정의하는 데 유용하다.
@Configuration에서 사용되는 @Bean은 아래에 정리해보았다.
- 여러 @Bean 메소드
- @Configuration이 설정된 클래스 안에는 여러개의 @Bean이 존재할 수 있다. 이 메소드들은 각각 다른 타입의 Bean을 반환하거나 같은 타입의 Bean을 반환할 수 있다.
- 싱글톤 관리
- @Bean 메소드가 반환하는 인스턴스는 각각 하나만 존재한다.
- 각 @Bean 메소드에서 생성된 인스턴스는 Spring 컨테이너에 의해 관리된다.
- 그리고 해당 Bean은 애플리케이션이 실행되는 동안 하나의 인스턴스만 존재한다는 말이다. 하나의 인스턴스만 존재한다는 말은 해당 @Bean이 속한 클래스에서 유일하게 존재해야 한다는 의미이다.
- 각 인스턴스가 애플리케이션 전반에 걸쳐 재사용되며, 상태를 공유한다. 즉, 이 인스턴스의 상태가 변경되면 모든 사용자가 그 변경된 상태를 참조하게 된다.
예시 - @Configuration에서 사용되는 @Bean 예시
// controller 예시
@Configuration
public class AppConfig {
@Bean
public MyService myService() {
return new MyService();
}
@Bean
public MyRepository myRepository() {
return new MyRepository(myService()); // myService() 호출로 의존성 주입
}
}
- @Configuration 어노테이션 안에 @Bean이 있다.
- 각각의 @Bean 메소드는 유일한 인스턴스를 반환한다. 이 인스턴스는 내부 상태를 가질 수 있어 값이 변경될 수 있다.
@EnableWebSecurity
- Spring Security에서 웹 보안을 활성화하는 어노테이션.
- @EnableWebSecurity 어노테이션이 붙은 클래스는 웹 보안 구성을 위한 설정 파일임을 나타내고, Spring Secuity의 기본 웹 보안 기능이 이 클래스에서 활성화된다.
- 내부적으로 여러 필터들이 자동으로 설정되어 인증(authentication), 권한 부여(authorization) 등을 처리하는 필터 체인을 구성하게 된다.
- HTTP 요청에 대한 보안 처리가 가능해지며, 여기서 작성한 보안 설정(HttpSecurity를 통해 정의한 설정 등)이 적용된다.
SecurityFilterChain
- 클라이언트의 모든 HTTP 요청을 필터링하는 보안 필터 체인.
- Spring Security에서 보안 필터의 연쇄(chain)를 구성하는 인터페이스다.
- Spring Security의 보안 필터들은 SecurityFilterChain에 의해 구성되며, 요청이 들어오면 이 필터 체인을 거쳐서 인증과 권한 검사가 수행한다.
- 필터 체인에는 여러 보안 관련 필터들이 연결되어 있는데, 예를 들어 UsernamePasswordAuthenticationFilter, CsrfFilter, SessionManagementFilter 등이 포함되어 있다.
- 클라이언트 요청이 들어오면 SecurityFilterChain이 먼저 그 요청을 가로채 필터 체인 내의 필터들이 요청에 대해 하나씩 인증, 권한 부여 등의 작업을 수행한다.
- 예를들어 HttpSecurity 클래스를 사용하여 필터 체인에 어떤 필터를 넣을지, 어떤 보안 규칙을 적용할지 정의한다.
예시 - SecurityFilterChain과 함께 사용되는 @Configuration 예시
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
log.info("security config ...");
http
.formLogin(formLogin -> formLogin
.loginPage("/login")
.defaultSuccessUrl("/", true)
.permitAll()
)
.authorizeHttpRequests(authorize -> authorize
.requestMatchers("/", "/home", "/signup").permitAll()
.requestMatchers("/users", "/user/*/roles", "/user/*/role/**").hasRole("ADMIN")
.anyRequest().authenticated()
)
.logout(logout -> logout
.logoutSuccessUrl("/")
.permitAll()
);
return http.build();
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
SecurityFilterChain 동작 순서
- 요청 수신: 클라이언트가 서버에 HTTP 요청을 보낸다.
- SecurityFilterChain 호출: Spring Security가 요청을 가로채고, 등록된 SecurityFilterChain을 통해 요청을 처리한다.
- 필터 순차 실행: SecurityFilterChain 내의 필터들이 등록된 순서대로 실행된다. 일반적으로 다음과 같은 주요 필터들이 포함된다:
- SecurityContextPersistenceFilter: 요청에 대한 SecurityContext를 로드하고, 인증 정보를 저장한다.
- UsernamePasswordAuthenticationFilter (또는 다른 인증 필터): 사용자가 로그인 시 인증 정보를 확인한다. 로그인 폼에서 제출된 사용자 이름과 비밀번호를 검사한다.
- BasicAuthenticationFilter: HTTP Basic 인증을 처리한다.
- BearerTokenAuthenticationFilter: JWT와 같은 Bearer 토큰 인증을 처리한다.
- FilterSecurityInterceptor: 요청에 대한 인가(authorization)를 수행한다. 인증된 사용자가 해당 자원에 접근할 수 있는지 검사한다.
- ExceptionTranslationFilter: 보안 관련 예외를 처리하고, 적절한 응답을 생성한다.
- 인증 및 인가 처리:
- 각 필터는 설정된 규칙에 따라 요청을 처리하며, 인증되지 않은 경우 로그인 페이지로 리다이렉트하거나 에러 응답을 보낸다.
- 인증된 사용자인 경우, 요청이 계속 진행되며, 다음 필터로 넘어간다.
- 요청 전달: 모든 필터가 성공적으로 처리한 후, 최종적으로 요청이 실제 핸들러(컨트롤러)로 전달되어 비즈니스 로직이 실행된다.
- 응답 처리: 비즈니스 로직이 실행된 후, 응답이 생성되어 클라이언트에게 반환된다. 이 과정에서 추가적으로 처리할 필터가 있을 경우, 응답이 돌아오는 과정에서도 필터들이 실행될 수 있다.
HttpSecurity
- HTTP 요청에 대한 보안 설정을 정의하는 클래스.
- SecurityFilterChain이 필터를 통해 인증과 권한 검사를 하는데, 이 필터 체인에서 어떤 요청에 어떤 보안 규칙이 적용될지는 HttpSecurity에서 설정된다.
- 예를 들어, 로그인 페이지 경로, 인증이 필요한 URL, 접근 권한 부여 등을 설정할 수 있다.
- 사용자 요청이 필터 체인으로 들어온 경우
- HttpSecurity에서 설정한 규칙들이 적용된다. 예를 들어, 특정 경로(/login, /home)는 인증 없이 접근이 가능하고, 그 외의 경로는 인증이 필요하다고 설정한 경우, 이 설정이 필터 체인에 반영되어 동작한다.
- 인증이 필요할 경우, formLogin()으로 설정한 로그인 페이지로 리다이렉트된다.
HttpSecurity 클래스가 제공하는 메서드
1. authorizeHttpRequests()
- 요청에 대한 권한을 설정합니다.
- URL 패턴에 따라 접근 제어를 설정할 수 있다.
- * Spring Security 5.0 이후 버전에서는 authorizeRequests() 대신 authorizeHttpRequests() 메서드를 사용
2. formLogin()
- 기본 로그인 폼을 활성화한다.
- 커스터마이징할 수 있는 메서드들이 제공된다 (예: loginPage(), permitAll()).
3. logout()
- 로그아웃 관련 설정을 구성한다.
- 로그아웃 URL, 로그아웃 성공 후 이동할 URL 등을 설정할 수 있다.
4. csrf()
- CSRF(Cross-Site Request Forgery) 보호를 설정한다.
- 기본적으로 활성화되어 있지만, 필요에 따라 비활성화할 수 있다.
5. httpBasic()
- HTTP Basic 인증을 활성화한다.
- 사용자가 브라우저에서 사용자 이름과 비밀번호를 입력할 수 있도록 한다.
6. sessionManagement()
- 세션 관리 정책을 설정한다.
- 최대 세션 수, 세션 고유성 등을 관리할 수 있다.
7. exceptionHandling()
- 인증 및 권한 부여 실패 시 처리 방법을 정의한다.
- 사용자 정의 오류 페이지를 설정할 수 있다.
8. cors()
- CORS(Cross-Origin Resource Sharing) 설정을 구성한다.
외부 도메인에서의 요청 허용 여부를 설정할 수 있다.
예시 - HttpSecurity 클래스의 메서드의 사용 방법
// 예시
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests() // HTTP 요청에 대한 권한 설정
.antMatchers("/public/**").permitAll() // 공용 경로 접근 허용
.anyRequest().authenticated() // 나머지 요청은 인증 필요
.and()
.formLogin() // 로그인 폼 설정
.loginPage("/login") // 커스텀 로그인 페이지
.permitAll() // 모든 사용자에게 로그인 페이지 접근 허용
.and()
.logout() // 로그아웃 설정
.logoutUrl("/logout")
.logoutSuccessUrl("/"); // 로그아웃 성공 후 이동할 URL
}
헷갈리는 SecurityFilterChain, HttpSecurity 의 관계
쉽게 설명하자면 HttpSecurity가 "어떤 사용자만 특정 URL에 접근할 수 있다"라는 규칙을 설정했다고 하자. 그러면 이 설정을 통해 인증, 인가, 로그인 방식 등을 구체적으로 지정해줘야한다. 그런 다음 SecurityFilterChain이 HttpSecurity에서 설정한 규칙을 실제로 적용하는 필터 체인을 생성한다. 그래서 클라이언트로부터 요청이 들어오면 이 체인이 정의된 규칙에 따라 요청을 처리하는 역할을 한다.
요약하자면 HttpSecurity는 보안 설정을 만듦. SecurityFilterChain은 HttpSecurity가 만든 설정이 원활하게 이루어지도록 동작해줌.
예시를 살펴보면 .and() 가 있는 이유는..?
1. 가독성
설정이 체계적으로 구성되어 코드를 읽기 쉽게 만든다. 각 보안 설정이 블록으로 구분되어 있어 어떤 설정이 어떤 기능을 하는지 한눈에 알 수 있다.
2. 유연성
설정을 추가하거나 수정할 때, 코드의 흐름을 변경하지 않고도 쉽게 수정할 수 있다. 새로운 설정을 추가할 때 기존 구조를 유지할 수 있다.
3. 명확한 블록 구분
각 설정 블록의 종료를 명확히 하여, 설정 간의 관계를 이해하기 쉽게 해준다. 이는 특히 복잡한 보안 정책을 설정할 때 유용하다.
4. 기능 확장성
필요에 따라 설정을 더 추가하거나 커스터마이즈할 수 있는 유연성을 제공한다. 예를 들어, 다양한 인증 방식이나 접근 제어 로직을 간편하게 추가할 수 있다.
.and()의 역할
- Spring Security의 HttpSecurity 설정에서 메서드 체이닝을 위한 방법으로 사용된다.
- 이 메서드는 설정을 더 구조화하고 읽기 쉽게 만들어 주는 역할을 한다.
- 체이닝: HttpSecurity의 설정 메서드를 연속해서 호출할 수 있도록 해준다. 이를 통해 각 설정 블록을 구분하면서도 가독성을 높일 수 있다.
- 블록의 종료: 특정 설정 블록이 끝났음을 나타내며, 이후 다른 설정을 추가할 수 있는 공간을 제공한다. 예를 들어, authorizeHttpRequests() 설정이 끝나고 나서 로그인 설정이나 로그아웃 설정을 이어서 할 수 있게 해준다.
참고
'Java > SpringBoot' 카테고리의 다른 글
CustomUserDetails 클래스Builder 적용, JPA 활용한 UserEntity (0) | 2024.10.28 |
---|---|
UserDetailsService, UserDetails, GrantedAuthority, SimpleGrantedAuthority, stream (0) | 2024.10.28 |
@Param (0) | 2024.10.28 |
@ModelAttribute (1) | 2024.10.28 |
@RequestParm (0) | 2024.10.28 |