DefaultSecurityFilterChain에 기본적으로 등록되는 필터로 열한 번째에 위치하는 BasicAuthenticationFilter에 대해 알아보자.
BasicAuthenticationFilter는 Basic 기반의 인증을 수행하기 위해 등록된다.
커스텀 SecurityFilterChain을 생성하면 자동 등록이 안되기 때문에 아래 구문을 통해서 필터를 활성화시켜야 한다.
http
.httpBasic(Customizer.withDefaults());
Basic 인증을 자세하게 설명하기 위해 Form 인증 방식과 비교해보자!
Form 인증 방식은 Form 태그에 username/password를 입력 후 브라우저에서 서버로 전송하면 서버는 상태에 알맞은 세션 또는 JWT를 생성하여 사용자를 기억할 수 있도록 한다.
Basic 인증 방식은 브라우저에서 제공하는 입력기에 username/password를 입력하면 브라우저가 매 요청 시 BASE64로 인코딩하여 Authorization 헤더에 넣어서 전송한다. 서버는 요청에 대해 username/password만 확인 후 사용자를 기억하지 않기 때문에 매 요청 시 Authorization 헤더가 요구된다.
하지만?!
스프링 시큐리티의 Basic 인증 로직은 매번 재인증을 요구하는 것이 아닌 세션에 값을 저장해서 유저를 기억한다. (Authorization 헤더는 필요하다)
※ 요청 형식
Authorization: Basic BASE64로인코딩한usernamepassword값
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 인증을 위한 팝업 창이다.
브라우저에서 제공하는 기능으로 브라우저별로 다른 화면이 발생한다.