SpringBoot

[SpringBoot] ThreadLocal을 활용한 인증관리

코카멍멍 2024. 6. 20. 19:26
반응형

스프링부트는 ThreadPool을 통해 스레드를 미리 생성하고 요청에 맞게 쓰레드를 배정하고 응답이 끝나면 쓰레드를 반환합니다.

저는 이 쓰레드를 이용해 인증을 통과한 사용자일 때 ThreadLocal에 사용자의 ID를 삽입하여 전역적으로 사용할 수 있게 하려고 했습니다.

문제점 발생!!

하지만 처음에 인증에 성공하여 ThreadLocal에 저장되고 초기화 하지 않았을 때 다음 사용자가 인증에 실패해도 전에 사용자의 정보가 남아있어 비즈니스 로직이 실행되는 문제가 발생했습니다.

아래 예시들을 통해 설명드리겠습니다.

1번 요청의 사용자는 1이라는 값을 통해 인증을 수행합니다.

인증 로직을 통과하고 전역적으로 사용할 수 있는 쓰레드에 1이라는 값을 저장합니다.

1번 사용자가 요청한 비즈니스 로직을 끝맡히고 쓰레드풀에 쓰레드를 반환합니다.

2번 사용자가 허용하지 않는 인증값을 가지고 요청하게 됩니다.

인증로직에 통과하지 않아 Thread에 값이 담기기 전에 다음 로직으로 넘어가게 됩니다.

기존에 저장되있던 id를 이용해서 비즈니스로직이 문제없이 실행됐습니다.

문제는 여기서 발생합니다. 해당 사용자가 권한이 없음에도 불구하고 다른 사용자의 정보를 이용해 비즈니스로직을 실행했습니다. 이렇게 되면 예상치 못한 요청이 발생할 수 있으며 로그를 확인했을 사용자의 잘못인지 개발자의 잘못인지 찾기가 어렵습니다.

그렇다면 어떻게 해결해야 할까요?

해결방안

사실 해결방안은 굉장히 간단합니다.

Thread에 저장돼있는 값을 null로 초기화 해주면 됩니다.

해당 실제 발생 상황

요청이 올때마다 쓰레드를 배정하는데 그 쓰레드를 이용해 AuthHolder 객체의 필드에 idx를 저장해 Controller, Service단에서 사용했었습니다.

Token

eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiI1MCIsInJvbGUiOiJDT05TVU1FUiIsImlhdCI6MTY5MjQzODIwMSwiZXhwIjoxNjkzMDQzMDAxfQ.fBR4CoLLjx2xfoXVbIYLRrh7FdrJN1XgxJ9fCZNJkzc

한번 로그인 테스트를 한 후 토큰을 제외하고 다시 실행했습니다

Token

null

결과는 토큰이 없는데도 아까 조회했던 유저의 정보를 가져왔습니다.

해결 코드

Filter가 끝나고 난 후에 ThreadLocal에 저장돼 있는 값을 초기화 해주었습니다.

반응형