[chap.17] BasicAuthenticationFilter

BasicAuthenticationFilter

BasicAuthenticationFilter 목적

  • 이 필터는 DefaultSecurityFilterChain 에 기본적으로 등록되는 필터이며, 열한 번째에 위치한다.
  • HTTP Basic 인증을 처리하는 핵심 필터이다.
  • Basic 인증은 RFC 7617에서 정의된 표준 인증 방식으로, 간단하면서도 효과적인 인증 메커니즘을 제공한다.

필터 활성화 방법

Java
http.httpBasic(Customizer.withDefaults());

Basic 인증의 특징과 동작 방식

Form 인증과의 차이점

Form 인증

  • 사용자가 웹 폼에 직접 입력
  • 세션 또는 JWT 기반의 상태 유지
  • 일회성 인증 후 토큰/세션으로 관리

Basic 인증

  • 브라우저 기본 제공 대화상자 사용
  • 매 요청마다 인증 정보 전송
  • Base64 인코딩된 credentials 사용
  • 헤더 기반 인증 방식

인증 헤더 구조

기본 형식

Plaintext
Authorization: Basic {Base64Encoded(username:password)}

예시

Plaintext
// username: user, password: pass123 인 경우
Authorization: Basic dXNlcjpwYXNzMTIz

Spring Security 의 Basic 인증 구현

최적화된 기능

  • 세션 통합
    • 인증 정보를 세션에 캐싱
    • 불필요한 재인증 방지
  • Remember-Me 서비스
    • 장기간 인증 유지 가능
    • 사용자 편의성 향상

BasicAuthenticationFilter 클래스

Java
public class BasicAuthenticationFilter extends OncePerRequestFilter {
  
}

주요 로직 : doFilterInternal

Java
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
  throws IOException, ServletException {

  try {

    // HTTP Authorization 헤더에서 값을 꺼냄
    Authentication authRequest = this.authenticationConverter.convert(request);
    if (authRequest == null) {
      this.logger.trace("Did not process authentication request since failed to find "
        + "username and password in Basic Authorization header");
      chain.doFilter(request, response);
      return;
    }

    // username 값을 가져옴
    String username = authRequest.getName();
    this.logger.trace(LogMessage.format("Found username '%s' in Basic Authorization header", username));

    // Security Context에 해당 username이 이미 존재하는지 확인
    if (authenticationIsRequired(username)) {
      // 인증 진행
      Authentication authResult = this.authenticationManager.authenticate(authRequest);
      // 인증 결과를 Security Context에 저장
      SecurityContext context = this.securityContextHolderStrategy.createEmptyContext();
      context.setAuthentication(authResult);
      this.securityContextHolderStrategy.setContext(context);
      if (this.logger.isDebugEnabled()) {
        this.logger.debug(LogMessage.format("Set SecurityContextHolder to %s", authResult));
      }
      // Remember Me 서비스에 등록
      this.rememberMeServices.loginSuccess(request, response, authResult);
      // Security Context Repository에 저장
      this.securityContextRepository.saveContext(context, request, response);
      // 로그인 성공 핸들러
      onSuccessfulAuthentication(request, response, authResult);
    }
  } catch (AuthenticationException ex) {
    this.securityContextHolderStrategy.clearContext();
    this.logger.debug("Failed to process authentication request", ex);
    this.rememberMeServices.loginFail(request, response);
    onUnsuccessfulAuthentication(request, response, ex);
    if (this.ignoreFailure) {
      chain.doFilter(request, response);
    } else {
      this.authenticationEntryPoint.commence(request, response, ex);
    }
    return;
  }

  chain.doFilter(request, response);
}

주요 처리 단계

  • 헤더 검증 단계
    • Authorization 헤더 존재 확인
    • Basic 인증 방식 확인
    • Base64 디코딩 및 유효성 검사
  • 인증 처리 단계
    • SecurityContext 확인
    • AuthenticationManager를 통한 인증
    • 인증 결과 처리
  • 보안 컨텍스트 관리
    • SecurityContext 업데이트
    • Remember-Me 서비스 연동
    • 세션 관리

예외 처리 로직

Java
try{
  // 인증 로직
  }catch(AuthenticationException ex){
  securityContextHolderStrategy.

clearContext();
    rememberMeServices.

loginFail(request, response);

onUnsuccessfulAuthentication(request, response, ex);
// ... 추가 예외 처리
}

보안 고려사항

전송 계층 보안

  • HTTPS 사용 필수
  • 평문 전송 위험 존재
  • TLS/SSL 적용 권장

인증 정보 보호

  • Base64는 인코딩일 뿐, 암호화가 아님
  • 네트워크 스니핑 위험 존재
  • 추가적인 보안 계층 필요

브라우저 호환성

  • 브라우저별 다른 UI/UX
  • 모바일 환경 고려 필요
  • 사용자 경험 최적화 필요

실제 활용 시나리오

API 서버 인증

  • REST API 엔드포인트 보호
  • 서비스 간 통신 인증
  • 마이크로서비스 아키텍처 적용

개발 및 테스트 환경

  • 빠른 프로토타입 구현
  • 테스트 자동화 용이
  • 개발 생산성 향상

참고 자료