Spring/Spring Securitiy
4. SecurityConfig 기본 사항
개발자잡
2025. 1. 22. 23:32
Spring Security를 사용해 백엔드를 구성할 때, 보통 SecurityConfig 클래스에서 구현해야할 사항들 정리
1. 프로젝트 의존성 확인
- Spring Boot를 사용한다면 spring-boot-starter-security를 의존성에 추가해야 합니다.
- Spring Security 버전에 따라 설정 방법이 조금씩 달라질 수 있으니, 사용하는 버전에 맞춰서 작성해야 합니다.
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-security'
// 다른 의존성들...
}
2. PasswordEncoder 설정
패스워드를 저장할 때는 반드시 평문(plain text)이 아닌 암호화된 형태로 저장해야 합니다. Spring Security에서는 BCryptPasswordEncoder나 Pbkdf2PasswordEncoder 등 다양한 인코더를 제공하고 있으므로, 원하는 구현체를 Bean으로 등록해두고 사용합니다.
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
3. 사용자 인증/권한(Authorization) 구성
(1) InMemoryUserDetailsManager를 활용한 예시
간단한 테스트용으로, 또는 데모 환경에서 사용할 때는 인메모리(In-Memory) 사용자 정보를 많이 씁니다.
@Bean
public UserDetailsService userDetailsService(PasswordEncoder passwordEncoder) {
UserDetails user = User.builder()
.username("user")
.password(passwordEncoder.encode("user1234"))
.roles("USER")
.build();
UserDetails admin = User.builder()
.username("admin")
.password(passwordEncoder.encode("admin1234"))
.roles("ADMIN")
.build();
return new InMemoryUserDetailsManager(user, admin);
}
(2) DB(데이터베이스)와 연동하는 예시
실제 운영 서비스에서는 사용자 정보를 DB에서 조회하여 인증/권한 부여를 하는 경우가 일반적입니다. 이 경우에는 UserDetailsService를 구현(또는 JdbcUserDetailsManager, JpaUserDetailsManager 등을 사용)하여, DB 접근 로직을 통해 UserDetails 객체를 반환하도록 구성합니다.
4. HTTP 보안(HTTP Security) 구성
Spring Security 6부터는 WebSecurityConfigurerAdapter가 아닌, SecurityFilterChain을 Bean으로 등록하는 방식의 구성(람다 기반) 사용이 권장됩니다.
@Configuration
@EnableWebSecurity
public class SecurityConfig {
// 1. PasswordEncoder Bean
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
// 2. UserDetailsService Bean
@Bean
public UserDetailsService userDetailsService(PasswordEncoder passwordEncoder) {
UserDetails user = User.builder()
.username("user")
.password(passwordEncoder.encode("user1234"))
.roles("USER")
.build();
UserDetails admin = User.builder()
.username("admin")
.password(passwordEncoder.encode("admin1234"))
.roles("ADMIN")
.build();
return new InMemoryUserDetailsManager(user, admin);
}
// 3. SecurityFilterChain Bean
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
// (1) CSRF 설정
.csrf(csrf -> csrf.disable())
// (2) 권한이 필요한 요청에 대한 설정
.authorizeHttpRequests(auth -> auth
// 인증 없이 접근을 허용할 경로
.requestMatchers("/public/**", "/css/**", "/js/**").permitAll()
// 특정 역할이 필요한 경로
.requestMatchers("/admin/**").hasRole("ADMIN")
// 그 외 나머지 요청은 인증이 필요
.anyRequest().authenticated()
)
// (3) 폼 로그인 설정
.formLogin(login -> login
.loginPage("/login") // 커스텀 로그인 페이지가 있다면 설정
.defaultSuccessUrl("/") // 로그인 성공시 이동 페이지
.permitAll() // 로그인 페이지는 누구나 접근 가능
)
// (4) 로그아웃 설정
.logout(logout -> logout
.logoutUrl("/logout")
.logoutSuccessUrl("/login?logout")
.invalidateHttpSession(true)
);
return http.build();
}
}
주요 설정 항목 설명
- csrf().disable()
- CSRF 보호를 사용하지 않도록 설정한 예시입니다. 일반적으로 API 서버의 경우 CSRF 공격 벡터가 제한적이므로 종종 비활성화하지만, 웹 애플리케이션(Form 기반)에서는 상황에 맞춰 활성화하는 것이 권장됩니다.
- authorizeHttpRequests()
- 요청 경로별 권한 설정. 예) /admin/**는 ADMIN 권한이 필요한 요청.
- formLogin()
- Form 기반 로그인을 사용하는 설정.
- logout()
- 로그아웃 처리 및 로그아웃 후 이동할 경로 설정.
5. 기타 고려 사항
- CORS 설정
- 프론트엔드와 분리되어 있는 환경에서 CORS 정책을 설정해야 한다면, http.cors() 설정(혹은 CorsConfigurationSource Bean 정의)을 통해 허용 도메인을 지정합니다.
- OAuth2 로그인
- 구글, 페이스북 등 소셜 로그인이나 OAuth2 방식을 사용할 때는 oauth2Login() 설정을 별도로 진행해야 합니다.
- 정적 리소스 (CSS, JS, 이미지 등) 허용
- 정적 리소스 접근에 대해서는 보안 필터를 거치지 않도록 permitAll() 처리를 자주 합니다.
- 예외 처리 (Exception Handling)
- 접근 권한이 없거나 인증되지 않은 사용자가 리소스에 접근할 때 보여줄 에러 페이지, 혹은 JSON 응답 등을 커스텀해야 할 수도 있습니다.
- http.exceptionHandling()을 통해 403, 401 등에 대한 처리를 따로 지정할 수 있습니다.
정리
- PasswordEncoder Bean: 비밀번호를 암호화하여 저장/비교하는 로직을 구현하기 위해 필요합니다.
- UserDetailsService Bean: 인증에 필요한 사용자 정보를 조회하는 핵심 로직을 작성합니다. (인메모리, DB, LDAP 등 다양한 소스 가능)
- SecurityFilterChain Bean: HttpSecurity를 통해 요청 경로별로 인증/권한을 부여하고, 폼 로그인/로그아웃 등 기본 보안 흐름을 구성합니다.
위와 같은 구성이 Spring Security를 활용하여 가장 기초적으로 구현해야 하는 설정들입니다. 운영 환경에 따라 OAuth2, JWT, Access-Control, 기타 복잡한 시나리오가 추가될 수 있습니다.