Spring Security의 인증과 인가

한눈에 보기

인증은 사용자가 누구인지 확인하는 과정이고 인가는 접근 권한을 판단하는 과정이다. Spring Security 6의 필터 체인 구조, AuthenticationManager 인증 흐름, SecurityFilterChain 설정을 정리한다.

최종 업데이트 2026.09.17

Spring Security에서 인증(Authentication)은 사용자가 누구인지 확인하는 과정이고, 인가(Authorization)는 확인된 사용자가 특정 자원에 접근할 권한이 있는지 판단하는 과정이다. Spring Security는 서블릿 필터 체인(Filter Chain) 위에서 이 두 과정을 처리하며, Spring Security 6과 Spring Boot 3.x에서는 SecurityFilterChain 빈(Bean)과 람다 DSL 기반 설정이 표준이다.

인증과 인가는 무엇이 다른가

인증은 "당신은 누구인가"에 대한 답이고, 인가는 "당신이 이것을 해도 되는가"에 대한 답이다. 인가는 인증 결과를 전제로 하므로 항상 인증 다음에 수행된다.

구분인증인가
질문사용자가 누구인가이 자원에 접근해도 되는가
수단아이디와 비밀번호, 토큰, 인증서권한(Authority), 역할(Role), 정책
실패 시 상태 코드401 Unauthorized403 Forbidden
담당 컴포넌트AuthenticationManager와 인증 필터AuthorizationManager와 AuthorizationFilter

필터 체인 구조

Spring Security의 모든 처리는 서블릿 필터로 구현된다. 서블릿 컨테이너에는 DelegatingFilterProxy라는 필터 하나만 등록되고, 이 프록시가 스프링 컨테이너 안의 FilterChainProxy 빈에게 처리를 위임한다. FilterChainProxy는 하나 이상의 SecurityFilterChain을 가지며, 요청 URL 패턴에 맞는 체인을 골라 그 안의 보안 필터들을 순서대로 실행한다. 체인에는 CSRF(Cross Site Request Forgery) 방어 필터, 로그인 처리 필터, 인증 정보 저장 필터, 예외 변환 필터, 마지막으로 인가를 담당하는 AuthorizationFilter 등이 포함된다. 서블릿 필터 기반이므로 디스패처 서블릿(DispatcherServlet)에 도달하기 전에 보안 검사가 끝난다는 점이 중요하다.

인증 처리 흐름

폼 로그인을 예로 들면 인증은 다음 순서로 진행된다.

  1. UsernamePasswordAuthenticationFilter가 로그인 요청에서 아이디와 비밀번호를 꺼내 미인증 상태의 Authentication 객체를 만든다.
  2. 이 객체를 AuthenticationManager에 넘긴다. 기본 구현인 ProviderManager는 등록된 AuthenticationProvider들에게 처리를 위임한다.
  3. DaoAuthenticationProvider가 UserDetailsService의 loadUserByUsername을 호출해 저장소에서 사용자 정보(UserDetails)를 조회한다.
  4. PasswordEncoder로 입력된 비밀번호와 저장된 해시를 비교한다. BCrypt가 기본 권장 인코더다.
  5. 검증에 성공하면 권한 목록이 채워진 인증 완료 Authentication 객체가 반환되고, SecurityContextHolder의 SecurityContext에 저장된다. 기본 저장 전략은 스레드 로컬(ThreadLocal)이므로 같은 요청을 처리하는 동안 어디서든 인증 정보를 꺼낼 수 있다.

JWT(JSON Web Token) 같은 토큰 인증도 구조는 같다. 커스텀 필터가 헤더에서 토큰을 꺼내 검증한 뒤, 인증된 Authentication을 SecurityContext에 넣어 주면 이후 인가 단계가 동일하게 동작한다.

인가 처리 흐름

인가는 체인의 마지막 부근에 있는 AuthorizationFilter가 담당한다. 이 필터는 요청과 SecurityContext의 Authentication을 AuthorizationManager에 넘겨 접근 허용 여부를 판단한다. URL 단위 규칙은 authorizeHttpRequests로 선언하고, 서비스 계층에서는 @EnableMethodSecurity를 켠 뒤 @PreAuthorize 같은 메서드 보안 애너테이션(Annotation)으로 세밀한 규칙을 건다.

@Service
public class AdminService {

    @PreAuthorize("hasRole('ADMIN')")
    public void deleteMember(Long memberId) {
        // ADMIN 역할이 있어야 호출할 수 있다
    }
}

인가에 실패했을 때 미인증 사용자라면 AuthenticationEntryPoint가 401 응답이나 로그인 페이지 이동을 처리하고, 인증은 되었지만 권한이 부족하면 AccessDeniedHandler가 403 응답을 처리한다.

설정 코드 예시

Spring Security 6에서는 WebSecurityConfigurerAdapter 상속 방식이 제거되었고, SecurityFilterChain을 빈으로 등록하는 방식만 사용한다.

@Configuration
@EnableWebSecurity
public class SecurityConfig {

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
            .csrf(csrf -> csrf.disable())
            .sessionManagement(session ->
                session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
            .authorizeHttpRequests(auth -> auth
                .requestMatchers("/api/auth/**").permitAll()
                .requestMatchers("/api/admin/**").hasRole("ADMIN")
                .anyRequest().authenticated());
        return http.build();
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
}

세션 없이 토큰으로 인증하는 REST API라면 위처럼 무상태 세션 정책을 쓰고 CSRF 방어를 끄는 구성이 일반적이다. 다만 브라우저 세션 기반 애플리케이션에서 CSRF를 끄는 것은 위험하므로, 인증 방식에 따라 판단해야 한다. 인가 규칙은 넓은 패턴보다 구체적인 패턴을 먼저 선언해야 의도대로 매칭된다는 점도 주의한다.

면접에서 이렇게 물어본다

  • 인증과 인가의 차이를 설명하고, 401과 403 상태 코드가 각각 어느 경우에 반환되는지 말해 보라.
  • DelegatingFilterProxy, FilterChainProxy, SecurityFilterChain의 관계를 설명해 보라.
  • 폼 로그인 요청이 들어왔을 때 AuthenticationManager와 UserDetailsService를 거쳐 인증이 완료되는 과정을 설명해 보라.
  • SecurityContextHolder가 스레드 로컬을 사용하는 이유와 그로 인한 주의점을 말해 보라.
  • JWT 기반 인증을 Spring Security 필터 체인에 어떻게 통합할 수 있는지 설명해 보라.
Spring / JPA 문서 전체 보기

이 개념, 내 코드에서는 어떻게 물어볼까요

데브핏(DevFit)에 채용공고 URL을 붙여 넣고 레포지토리를 연결하면, 내가 쓴 커밋에서 예상 질문과 어필 포인트를 만듭니다. 하루 10회까지 무료입니다. 합불 판정이나 지원자 랭킹은 만들지 않고, 최종 판단은 사람이 합니다.

공고 넣고 시작하기