-
모든 응답이 401로 의도한 대로 응답이 발생하지 않았습니다.
-
오류 발생 가능성이 있는 지점에 브레이크 포인트를 지정하고 디버그 모드로 순차적으로 점검하였습니다.
- 생성로직 -> 문제 없었습니다.
- 작성로직 -> 문제 없었습니다.
- Dto -> 문제 없었습니다.
- 디버그 결과 내부 로직에서는 문제를 발견하지 못했습니다.
-
401 에러가 우리 코드문제인지 시큐리티 문제인지 찾기 위해 시큐리티 엔트리포인트 에러 메시지를 변경 -> 시큐리티 에러 메시지를 확인했습니다.
-
DeferredResult 401 로 검색
-
스프링 시큐리티에서 응답시에도 SecurityContext를 읽어 권한체크를 하는데 이 때 다른 스레드에서 처리되어 인정권한을 읽어버리는 문제였음
- 비동기 요청을 처리하는 과정
- Spring Security 6 버전부터 SecurityContext를 관리하는 기본 방식인 SecurityContextHolderFilter를 사용합니다. SecurityContextHolderFilter는 이전 버전과 달리 SecurityContextRepository에 구현체를 등록하지 않으면 인증된 객체를 저장할 수 없기 때문입니다. DeferredResult는 응답 시 다른 스레드에 의해서 인증을 한 번 더 하게 되는데 이 경우 SecurityContext를 가져올 방법이 없어 401 에러가 발생했습니다.
- 시큐리티 설정 추가
http.securityContext((securityContext) -> securityContext
.securityContextRepository(new DelegatingSecurityContextRepository(
new RequestAttributeSecurityContextRepository(),
new HttpSessionSecurityContextRepository()
))
);
- 해결
- DelegatingSecurityContextRepository
- SecurityContextRepository 구현체를 체인으로 연결합니다.
- 연결된 목록을 순회하며 SecurityContext를 저장하거나 복원하는데 사용됩니다.
- RequestAttributeSecurityContextRepository
- SecurityContext를 HTTP 요청의 속성으로 저장하고 복원할 때 사용됩니다.
- 현재 요청을 처리하는 동안 스레드 간 SecurityContext를 올바르게 전파하여 비동기 작업의 문제점을 해결 할 수 있습니다.
- SecurityContext를 세션에 저장하고 복원합니다.
- 현재 세션을 공유하는 모든 스레드에서 SecurityContext가 올바르게 전파될 수 있도록 합니다.
레퍼런스