@@ -0,0 +1,85 @@
+package nextstep.security.filter;
+
+import jakarta.servlet.Filter;
+import jakarta.servlet.FilterChain;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.ServletRequest;
+import jakarta.servlet.ServletResponse;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+import nextstep.security.AuthenticationException;
+import nextstep.security.config.Authentication;
+import nextstep.security.config.AuthenticationManager;
+import nextstep.security.config.BasicAuthenticationToken;
+import nextstep.security.config.SecurityContext;
+import nextstep.security.config.SecurityContextHolder;
+
+import java.util.List;
+
+import static org.springframework.http.HttpHeaders.AUTHORIZATION;
+
+public class BasicAuthFilter implements Filter {
+
+    private static final List<String> TARGET_URL = List.of("/members");
+
+    private final AuthenticationManager authenticationManager;
+
+    public BasicAuthFilter(AuthenticationManager authenticationManager) {
+        this.authenticationManager = authenticationManager;
+    }
+
+    @Override
+    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws ServletException {
+        boolean isHttpServlet = servletRequest instanceof HttpServletRequest && servletResponse instanceof HttpServletResponse;
+        if (isHttpServlet) {
+            HttpServletRequest request = (HttpServletRequest) servletRequest;
+            HttpServletResponse response = (HttpServletResponse) servletResponse;
+
+            try {
+                boolean notTarget = isNotTarget(request);
+                if (notTarget) {
+                    filterChain.doFilter(request, response);
+                    return;
+                }
+                // 타겟일 경우
+                checkAuthentication(request);
+                filterChain.doFilter(request, response);
+            } catch (Exception e) {
+                response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
+            }
+            return;
+        }
+        throw new ServletException("BasicAuthFilter only supports HTTP requests");
+    }
+
+    private boolean isNotTarget(HttpServletRequest request) {
+        String requestURI = request.getRequestURI();
+        return TARGET_URL.stream()
+                .filter(requestURI::startsWith)
+                .findAny()
+                .isEmpty();
+    }
+
+    private void checkAuthentication(HttpServletRequest request) {
+        String authorizationHeader = getAuthorizationHeader(request);
+        if (authorizationHeader == null) throw new AuthenticationException("Missing authorization header");
+
+        Authentication authentication = authenticationManager.authenticate(new BasicAuthenticationToken(authorizationHeader));
+        if (!authentication.isAuthenticated()) {
+            throw new AuthenticationException();
+        }
+        saveToSecurityContext(authentication);
+    }
+
+    private void saveToSecurityContext(Authentication authentication) {
+        SecurityContext securityContext = SecurityContextHolder.createEmptyContext();
+        securityContext.setAuthentication(authentication);
+        SecurityContextHolder.setContext(securityContext);
+    }
+
+    private String getAuthorizationHeader(HttpServletRequest request) {
+        return request.getHeader(AUTHORIZATION);
+    }
+
+
+}

리뷰: > 한가지 이해가 안되는게 있는데, 마지막에 BasicAuthentication과 UsernamePasswordAuthentication이 있을때, 세션이 있다면 BasicAuthentication에서 인증할 필요가 없도록 구조를 바꿔야하는게 맞을까요?

스프링 시큐리티를 구현하며 학습하고 있기 때문에 스프링 시큐리티 구조가 기준점이 되긴 하는데요.
스프링 시큐리티가 정답이라는 틀에서 벗어나 직접 설계를 고민해보면 더 의미 있는 학습이 될 것 같아요!

세션이 있을 때 인증을 한다면 어떠한 장점이 있고, 항상 수행하면 어떤 장점이 있을지 고민 후 준호님의 설계에 맞춰 트레이드 오프를 선택해보면 좋을 것 같은데요.
준호님이 생각하시는 장단점은 어떤 것이 있을까요?
그리고 지금 설계에서 어떤 부분을 더 중요하게 고려하고 싶은지도 궁금합니다 ㅎㅎ