[데브코스] Spring Boot 인증·인가(Auth) (52강) - getActor 메서드 리팩토링과 Rq 유틸 메서드 분리

zuno·2026년 1월 20일

이번 강의에서는 Rq.getActor() 메서드에 점점 쌓여가던 인증 관련 로직을 정리하고,
중복되는 책임을 메서드로 분리하는 리팩토링을 진행했다.

핵심은 인증 로직 자체는 유지하면서, 가독성과 안전성을 높이는 것이다.


리팩토링 전 문제점

기존 getActor() 메서드는 다음과 같은 문제를 가지고 있었다.

  • req.getHeader()가 null을 반환할 수 있음
  • req.getCookies() 역시 null일 수 있음
  • Authorization 헤더 처리 로직과 Cookie 처리 로직이 한 메서드에 섞여 있음
  • null 체크 + 문자열 검증 로직이 길어짐
  • 테스트는 통과하지만 코드가 읽기 어려워짐

즉, 동작은 맞지만 유지보수성이 좋지 않은 상태였다.


리팩토링 목표

이번 리팩토링의 목표는 다음과 같다.

  • null 체크를 Optional로 안전하게 처리
  • Header 접근 로직을 별도 메서드로 분리
  • Cookie 접근 로직을 별도 메서드로 분리
  • getActor()는 “인증 흐름”만 담당하도록 단순화

1️⃣ req.getCookies() null 체크를 Optional로 처리

Servlet API의 req.getCookies()는 쿠키가 없을 경우 null을 반환한다.

이를 그대로 사용하면 NPE 위험이 있기 때문에 Optional로 감싸 처리했다.

private String getCookieValue(String name, String defaultValue) {
    return Optional
            .ofNullable(req.getCookies())
            .flatMap(cookies ->
                    Arrays.stream(cookies)
                            .filter(cookie -> cookie.getName().equals(name))
                            .map(Cookie::getValue)
                            .filter(value -> !value.isBlank())
                            .findFirst()
            )
            .orElse(defaultValue);
}

이 방식의 장점

  • null 체크 코드 제거
  • 쿠키 탐색 로직이 한 곳에 모임
  • 재사용 가능

2️⃣ Authorization 헤더 접근 로직 분리

req.getHeader() 역시 값이 없으면 null을 반환한다.
이를 직접 사용하지 않고 전용 메서드로 감쌌다.

private String getHeader(String name, String defaultValue) {
    return Optional
            .ofNullable(req.getHeader(name))
            .filter(headerValue -> !headerValue.isBlank())
            .orElse(defaultValue);
}

이제 getActor()에서는 헤더가 있는지 없는지를 직접 신경 쓸 필요가 없다.


3️⃣ getActor() 메서드 리팩토링 결과

리팩토링 이후 getActor()는 인증 흐름만 명확하게 보여주는 코드가 되었다.

public Member getActor() {
    String headerAuthorization = getHeader("Authorization", "");
    String apiKey;

    if (!headerAuthorization.isBlank()) {
        if (!headerAuthorization.startsWith("Bearer "))
            throw new ServiceException("401-2", "Authorization 헤더가 Bearer 형식이 아닙니다.");

        apiKey = headerAuthorization.substring("Bearer ".length()).trim();
    } else {
        apiKey = getCookieValue("apiKey", "");
    }

    if (apiKey.isBlank())
        throw new ServiceException("401-1", "로그인 후 이용해주세요.");

    return memberService
            .findByApiKey(apiKey)
            .orElseThrow(() -> new ServiceException("401-3", "API 키가 유효하지 않습니다."));
}

리팩토링 후 구조의 장점

  • 인증 흐름이 한눈에 보임
  • Header / Cookie 처리 책임이 분리됨
  • null 관련 방어 로직이 중앙화됨
  • 이후 인증 방식 추가 시 확장하기 쉬움

핵심 정리

  • HttpServletRequest는 null을 자주 반환한다
  • Optional은 “값이 있을 수도, 없을 수도 있음”을 코드로 표현하기 좋다
  • 인증 로직은 짧고 명확해야 한다
  • 동작하는 코드보다 읽히는 코드가 더 중요하다

0개의 댓글