문제

401 - Full authentication is required to access this resource
org.springframework.security.access.AccessDeniedException: Access Denied

최근에 팀 프로젝트 진행하면서 Long polling을 이용하여 알림기능을 구현하였다.

이 과정에서 DeferredResult와 Spring security 같이 사용하게 되었는데, 요청 시에는 정상적으로 인증이 되었어도 응답 시에 401 Unauthorized가 반환되는 상황이 발생했다.

이슈가 발생했던 코드는 아래와 같다.

@GetMapping(value = "/subscribe")
public DeferredResult<List<NotificationResponse>> getNewNotifications(Principal principal) {
    // 사용자 정보 가져오기
    Member member = memberService.getMemberByUsername(principal.getName());

    // DeferredResult 생성 및 저장소에 저장
    DeferredResult<List<NotificationResponse>> deferredResult =
            notificationService.getDeferredResult(member.getId().toString());

    deferredResult.onTimeout(() -> {
        deferredResult.setErrorResult(new NoMoreNotificationException());
    });

    return deferredResult;
}

해결 시도

원인을 파악하기 위해 일주일이라는 정말 많은 시간이 소요 되었다.

그만큼 원인을 파악하기 힘들었는데, 그 과정을 조금 공유해볼까 한다.

비동기 처리 시 SecurityContext 미전파

처음에는 단순히 비동기 처리 시 SecurityContext가 자식 스레드에 전파되지 않아서 발생한 문제로 파악했었다.

DeferredResult는 비동기로 요청을 처리해야할 때 사용되는데, 이로 인해 중간에 SecurityContext를 잃어버려 발생하는 이슈로 짐작을 하고 있었다.

DelegatingSecuritContextRunnable/Callable

DelegatingSecurityContextRunnable 를 사용하여 비동기 처리 시에도 해당 스레드에도 SecurityContext를 전파할 수 있다.

그렇기에 아래와 같이 코드를 작성하여 SecurityContext 전파를 시도하였지만, 해결책이 되지는 못했다.