개발놀이터

SSO (부제 : Spring Security CAS) 본문

Spring/Spring Security

SSO (부제 : Spring Security CAS)

마늘냄새폴폴 2024. 2. 25. 21:52

서로 물리적으로 분리된 서버끼리 사용자의 로그인 상태를 유지하고 싶으면 어떻게 해야할까요? 

 

저는 이 문제 상황에서 제일 먼저 떠오른 것이 상태저장 데이터베이스를 중간에 두는 것이었습니다. 

 

 

사용자가 A서버에 로그인하면 쿠키에 간단한 값을 저장합니다. 예를 들어서 회원의 인덱스를 저장한다고 해보죠 그 값을 1이라고 가정하겠습니다. 

 

그리고 동시에 Redis와 같은 캐시, 세션 저장소에 1이라는 값을 씁니다. 

 

만약 B서버에 사용자가 접근하면 쿠키 값을 읽고 회원 인덱스가 존재하니 Redis에 해당 값을 조회해봅니다. 그리고 존재하기 때문에 MySQL과 같은 RDBMS에서 회원을 조회하고 그 값을 토대로 Spring Security에서 제공해주는 SecurityContextHolder에 Authentication 객체를 집어넣어서 인증을 완료하면 됩니다. 

 

어? 꽤 간단해보입니다? 

 

근데 서버가 두개가 아니고 여러개면 어떻게 해야될까요? 마이크로 서비스 아키텍처처럼 같은 서비스지만 모든 도메인마다 서버가 나누어져 있으면요? 

 

그럴때마다 세션 데이터베이스에 조회해서 RDB에 조회를 요청하기엔 데이터베이스에 부하가 우려됩니다. 

 

그럼 이를 위해서 데이터베이스 레플리케이션같은 솔루션을 사용해야할까요? 그것도 좀 아닌거같고...

 

어떡하죠?

 

SSO (Single Sign On)

SSO는 인증 서버를 이용해 인증을 구현하는 것입니다. 

 

순서는 이렇게 됩니다. 

 

해당 순서는 로그인을 하지 않은 최초의 상황입니다. 

  1. 사용자가 인증이 필요한 A서버의 서비스에 요청한다
  2. 웹서버가 A서버로 사용자의 트래픽을 유도한다
  3. A서버에서 인증되지 않은 사용자로 판단하여 Exception을 터트린다. 
  4. 해당 Exception을 핸들링하는 Filter에 의해 인증서버로 Redirect된다.
  5. 인증 서버에서 로그인을 수행하고 로그인때 입력한 값을 A서버로 티켓형태로 Redirect해준다
  6. A서버에서 데이터베이스를 뒤지면서 티켓을 검증한다. 
  7. 검증된 티켓을 다시 인증서버에 전송한다. 동시에 A서버에서 인증절차를 통해 인증을 마무리한다. 
  8. 해당 티켓을 인증서버에서 저장하고 있는다.

 

그리고 인증이 필요한 B서버의 서비스로 사용자의 요청이 들어오면 다음과 같은 순서를 가집니다. 

 

  1. 사용자가 인증이 필요한 B서버의 서비스에 요청한다.
  2. 웹서버가 B서버로 사용자의 트래픽을 유도한다.
  3. B서버에서 인증되지 않은 사용자로 판단하여 Exception을 터트린다. 
  4. 해당 Exception을 핸들링하는 Filter에 의해 인증서버로 Redirect된다. 
  5. 인증 서버에서 사용자와 일치하는 티켓을 찾아본다. 
  6. 티켓이 존재하므로 B서버로 인증완료 티켓과 함께 다시 Redirect한다. 
  7. B서버에서 인증완료 티켓을 기반으로 인증을 마무리한다. 

 

이런 절차를 거치게 됩니다. 

 

그런데 인증서버를 직접 구현하기엔 조금 무리가 있어보이긴 합니다. 좀 복잡해보이지 않나요? 

 

하지만 개발자는 항상 비슷한 문제상황을 겪고 있었고 하는 생각은 다 거기서 거기입니다. Spring에선 이런 SSO를 구현하기 위해 CAS라는 오픈소스를 제공하고 있습니다. 

 

다음 시간엔 CAS를 어떻게 배포할 것인지 실습하면서 알아보도록 하죠.