문제 상황
시큐리티 프로젝트를 따라 가면서 작동 원리를 이해 해보자
요구 사항
기본 보안 설정과 기본 사용자를 구성한다.
필요 개념
SecurityFilterChain
SecurityFilterChain은 Spring Security에서 사용자가 정의한 보안 필터들이 순차적으로 적용되는 체인(chain)을 의미한다. 이 필터 체인은 클라이언트 요청을 처리하는 여러 보안 필터들의 묶음으로, 요청이 들어올 때 각 필터가 순서대로 실행되어 보안 처리를 담당한다. Spring Security에서 인증 및 인가(Authentication, Authorization)와 관련된 주요 작업들이 이 필터 체인을 통해 이루어진다.
역할
SecurityFilterChain은 각 HTTP 요청을 처리할 때 필터를 적용하는 방식을 정의하며, 요청이 애플리케이션에 도달하기 전에 다양한 보안 관련 검사를 진행한다. 예를 들어:
- 인증(Authentication): 사용자가 적절한 인증 수단(예: ID/PW, OAuth2 토큰)을 통해 본인 확인을 하는지 검증.
- 인가(Authorization): 인증된 사용자가 해당 요청에 대해 권한이 있는지 확인.
- CORS 필터: 다른 도메인으로부터의 요청이 허용되는지 검사.
- CSRF 필터: 크로스 사이트 요청 위조(Cross-Site Request Forgery) 공격을 방어.
- 세션 관리: 세션 타임아웃이나 동시 세션 제한 같은 기능을 구현.
UserDetailsService
UserDetailsService는 Spring Security에서 사용자 인증을 처리하기 위한 핵심 인터페이스 중 하나다. 이 인터페이스는 애플리케이션에서 사용자의 정보를 가져와 Spring Security에서 인증을 처리할 수 있도록 사용자 객체(UserDetails)를 반환하는 역할을 한다.
주요 역할
UserDetailsService는 데이터베이스나 다른 외부 시스템에서 사용자의 정보를 로드하여, 인증 과정에서 사용자의 정보를 검증하는 데 필요한 데이터를 제공한다. 주로 사용자 이름(또는 이메일)과 비밀번호를 기반으로 사용자를 검색하며, 결과로 UserDetails 객체를 반환한다. 이 객체에는 사용자의 권한 정보, 계정 상태, 비밀번호 등이 포함된다.
코드 설명
@Configuration // 이 클래스가 스프링의 설정 클래스를 나타냄
@EnableWebSecurity // 스프링 시큐리티를 활성화하며, 이 클래스가 시큐리티 설정 클래스임을 명시
@RequiredArgsConstructor // final 필드를 자동으로 생성자 주입하는 Lombok 어노테이션
public class SecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
// SecurityFilterChain을 구성하는 Bean 정의. 이 메서드에서 HTTP 보안 설정을 구성함.
http
.authorizeHttpRequests(auth -> auth
// authorizeHttpRequests: HTTP 요청에 대한 인증 및 권한 부여 규칙을 설정
.requestMatchers("/").permitAll()
// requestMatchers("/"): "/" 경로에 대해 모든 사용자에게 접근을 허용함 (로그인 필요 없음)
.anyRequest().authenticated())
// anyRequest(): 그 외의 모든 요청은 인증된 사용자만 접근 가능하게 설정
.formLogin(Customizer.withDefaults());
// formLogin: 기본 폼 기반 로그인을 활성화. Spring Security가 제공하는 기본 로그인 페이지를 사용함.
// Customizer.withDefaults(): 추가적인 커스텀 설정 없이 기본 설정을 사용함
return http.build();
// 설정이 완료된 SecurityFilterChain 객체를 반환하여 Spring Security가 이를 사용하게 함
}
}
Spring Security의 기본적인 설정을 나타내며, 루트 URL(/)은 모든 사용자에게 허용하고, 그 외의 모든 URL은 인증된 사용자만 접근할 수 있도록 설정한다. 기본적인 폼 기반 로그인을 제공하고, 별도의 커스텀 설정 없이 기본 로그인 페이지를 사용하게 된다.
HttpSecurity를 통해 요청에 대한 접근 권한을 정의하고, 인증되지 않은 사용자는 기본 로그인 페이지로 리다이렉트된다.
@Bean
public UserDetailsService userDetailsService() {
// @Bean: 이 메서드를 Spring Bean으로 등록하여 스프링 컨테이너에서 관리하게 함.
// UserDetailsService: 사용자 정보를 제공하는 서비스. 스프링 시큐리티에서 사용자 인증을 처리할 때 사용됨.
UserDetails user = User.withUsername("user") // 사용자의 이름을 "user"로 설정함.
.password("{noop}1111") //{noop}: 비밀번호가 암호화되지 않았음을 나타냄. 실제로는 비밀번호를 암호화해야 하지만, {noop}을 사용하면 암호화 없이 그대로 비밀번호를 사용함.
.roles("USER") //사용자에게 "USER" 역할(role)을 부여함. 역할은 권한을 부여하는 데 사용됨.
.build(); // UserDetails 객체를 생성하여 반환함.
return new InMemoryUserDetailsManager(user);
// InMemoryUserDetailsManager: 메모리 내에서 사용자 정보를 관리하는 클래스.
// 이 경우, 생성된 user 객체를 메모리에 저장하고, 이를 기반으로 사용자 인증을 처리함.
// InMemoryUserDetailsManager는 사용자 정보를 메모리에 저장하므로, 서버를 재시작하면 데이터가 사라짐.
}
Spring Security에서 사용자를 인증하기 위해 InMemoryUserDetailsManager를 사용해, 메모리에 사용자 정보를 저장하는 방식. UserDetailsService는 사용자 정보를 제공하는 역할을 하고 여기서는 메모리 내에 사용자 정보를 등록해서 간단한 인증을 처리할 수 있도록 했다.
- UserDetailsService는 사용자 정보를 불러오는 인터페이스로, 이를 커스터마이징해서 DB나 다른 데이터 소스로부터 사용자 정보를 가져오도록 구현할 수 있다.
- InMemoryUserDetailsManager는 학습 단계에서 주로 사용하는 방식으로 간단하게 메모리 내에 사용자 정보를 저장하고 인증할 수 있게 준다