이번 강의(33강)는 한 줄로 요약하면 이거다.
👉 컨트롤러마다 반복되던 “Authorization 헤더 처리 + apiKey로 Member 조회” 로직을 Rq.getActor()로 옮겨서, 컨트롤러를 깔끔하게 만든다.
글/댓글 작성·수정·삭제 컨트롤러마다 아래 로직이 거의 똑같이 반복됐다.
Authorization 헤더 꺼내기"Bearer " 제거Member 조회예를 들면 (기존 방식 느낌):
String apiKey = authorization.replace("Bearer ", "");
Member actor = memberService.findByApiKey(apiKey)
.orElseThrow(() -> new ServiceException("401-1", "존재하지 않는 apiKey 입니다."));
이게 컨트롤러마다 있으면 뭐가 문제냐?
그래서 강의에서는 “이 중복을 한 곳으로 모으자” 라고 방향을 잡는다.
rq.getActor()만 호출컨트롤러에서 인증 관련 로직을 직접 하지 않고 이렇게 바뀐다.
Member actor = rq.getActor();
즉,
이번 강의의 핵심 구현은 Rq.getActor() 안에 들어간다.
@Component
@RequestScope
@RequiredArgsConstructor
public class Rq {
private final MemberService memberService;
private final HttpServletRequest req;
public Member getActor() {
String headerAuthorization = req.getHeader("Authorization");
if (headerAuthorization == null || headerAuthorization.isBlank())
throw new ServiceException("401-1", "Authorization 헤더가 존재하지 않습니다.");
if (!headerAuthorization.startsWith("Bearer "))
throw new ServiceException("401-2", "Authorization 헤더가 Bearer 형식이 아닙니다.");
String apiKey = headerAuthorization.substring("Bearer ".length()).trim();
Member member = memberService
.findByApiKey(apiKey)
.orElseThrow(() -> new ServiceException("401-3", "API 키가 유효하지 않습니다."));
return member;
}
}
이걸 “초보자 흐름”으로 풀면 이렇게 된다.
String headerAuthorization = req.getHeader("Authorization");
if (headerAuthorization == null || headerAuthorization.isBlank())
throw new ServiceException("401-1", "Authorization 헤더가 존재하지 않습니다.");
여기서 중요한 포인트:
헤더 자체가 없으면@NotBlank검증까지 도달하기 전에 터질 수 있음
(왜냐면 컨트롤러 파라미터 바인딩 단계에서 이미 문제가 생기기 때문)
if (!headerAuthorization.startsWith("Bearer "))
throw new ServiceException("401-2", "Authorization 헤더가 Bearer 형식이 아닙니다.");
String apiKey = headerAuthorization.substring("Bearer ".length()).trim();
substring("Bearer ".length()) : 앞의 "Bearer " 제거trim() : 혹시 공백 들어가도 정리Member member = memberService.findByApiKey(apiKey)
.orElseThrow(() -> new ServiceException("401-3", "API 키가 유효하지 않습니다."));
@RequestHeader("Authorization") String authorization를 받고Authorization 파라미터를 “굳이” 직접 받을 필요가 줄어듦rq.getActor()로 통일예시(수정된 형태 느낌):
public RsData<PostDto> write(@Valid @RequestBody PostWriteReqBody reqBody) {
Member actor = rq.getActor();
Post post = postService.write(actor, reqBody.title, reqBody.content);
...
}
즉, 컨트롤러에서 인증 로직이 사라지고 “내가 지금 해야 할 일”만 남는 구조가 된다.
이 부분은 헷갈리기 쉬워서 정리해둘게.
근데 컨트롤러가 ‘상태값을 필드에 저장’하지 않으면 덮어써질 게 없다.
그래서 보통 이런 코드는 안전하다:
public void something() {
String x = "..."; // 지역변수
}
예를 들어 이런 식이면 큰일남:
// (절대 하면 안 되는 예시)
@Component
public class AuthStore {
private Member currentActor; // 전역 상태
}
요청 A가 currentActor=user1 넣고,
요청 B가 currentActor=user2 덮으면,
요청 A가 다시 읽을 때 user2가 나올 수 있음 → 보안 사고.
결론부터 말하면:
new Rq()를 직접 안 한다그리고 중요한 사실:
✅ 요청 100개면 Rq도 100개 생기는 게 맞다
근데 그 생성은 스프링 컨테이너가 한다.
또 하나 더 중요한 포인트:
✅ 한 “요청” 안에서 rq.getActor()를 2번 호출해도
Rq 객체가 2개 생기는 게 아니라, 그 요청에 해당하는 Rq 1개를 계속 쓴다.
(요청 단위 1개 유지)
Rq.getActor()에 인증 로직을 모음Member actor = rq.getActor();만 쓰게 리팩토링이제 컨트롤러 코드가 “인증 처리 코드”에 묻히지 않고,
진짜 하고 싶은 비즈니스 로직만 남는 형태로 정리됐다.