Spring/시큐리티 기본원리

시큐리티 기본 원리( 18 ) - BasicAuthenticationFilter

_Jin_ 2025. 1. 28.

BasicAuthenticationFilter 목적 

해당 필터는 DefaultSecurityFilterChain에 있는 열한 번째 위치의 필터이다. 

 

필터가 수행하는 기능은 Basic 기반의 인증을 수행하기 위함이다.

만약, 커스텀 SecurityFilterChain을 생성하면 자동 등록이 되지 않기에 아래와 같은 설정을 통해서 별도로 활성화 시켜주어야한다. 

 

http
        .httpBasic(Customizer.withDefaults());

 

Basic 인증 ?

Basic 인증의 이해를 위해서 Form 인증 방식과 비교하며 파악해보자.

 

Form 인증 방식은 Form 태그에 username / password 등을 입력한 후에 브라우저에서 서버로 전송하면,

서버는 상태에 맞는 세션 or JWT를 생성하여 사용자를 기억할 수 있도록 동작한다.

 

한편, Basic 인증 방식은 브라우저에서 제공하는 입력기( ex 팝업창 )에 사용자 정보를 입력하면, 

이를 BASE64로 인코딩하여 Authorization 헤더에 넣어 서버에 요청한다. 

서버는 DB에서 해당하는 사용자를 찾고 존재하는 경우, 응답으로 클라이언트의 인증 정보를 담아 보낸다. 

그러면, 클라이언트는 받은 인증 정보를(사용자ID&비밀번호) 브라우저에 저장하는 것이 일반적인 Basic 인증 방식이다.

( stateless 하기에 요청마다 Authorization 헤더가 요구된다. )

 

하지만 스프링 시큐리티에서는 Basic 인증 로직을 매번 재인증을 요구하는 방식이 아닌 세션에 저장하여 유저를 기억하는

방식을 채택하였다.( 그럼에도 Authorization 헤더는 필요하다. )

요청 방식

브라우저에서 서버에 요청할 때, 헤더에 담기는 Authorization는 아래와 같은 모습을 지닐 것이다.

Authorization: Basic BASE64로인코딩한usernamepassword값

 

BasicAuthenticationFilter 주요 로직 

public class BasicAuthenticationFilter extends OncePerRequestFilter {
}

 

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);
}

 

 

브라우저에서 Basic 인증 방식

 

 

브라우저에서 제공하는 기능으로 브라우저별로 다른 화면이 발생한다.

댓글