[가자맵] spring-session-jdbc 중복로그인 방지

김상인·2023년 9월 3일
0

가자맵

목록 보기
4/8
post-thumbnail

spring-session-jdbc 을 사용하여 사용자의 중복 로그인을 방지하되
이메일 계정 하나에 웹 1개, 앱 1개씩만 로그인이 가능하도록 하고 싶었다.
어떻게 해야 될까?

public class PrincipalDetails implements UserDetails, OAuth2User {}

SecurityContextHolder 에 인증 객체가 저장되어 있어야 세션에 사용자 정보까지 DB에 저장되므로 앱은 UserDetails , 웹은 OAuth2User를 상속받아 구현하였다.
DB에 저장될 때는 위 객체가 SESSION_ATTRIBUTES 테이블에 직렬화되어 저장된다.

하고 있는 프로젝트에서는 소셜로그인으로만 인증하기 때문에
앱인지 웹인지 어디서 로그인을 했는지 쉽게 구분할 수 있었다.
그렇다면 PrincipalDetails 클래스 필드에 어느 플랫폼으로 로그인했는지 구분하는 값을 넣어준다면 쉽게 해결할 수 있을 거라고 생각했다.

해결 방법

공식 문서에 아주 친절하게 예제 코드까지 나와있다.
객체를 역.직렬화 할 수 있도록 Serializable 를 상속받은 클래스를 만들면 Session에 추가로 데이터를 넣을 수 있다.

그래서 세션에 추가로 데이터를 넣을 클래스를 만들어주고

public class PrincipalDetails extends SessionDetails implements UserDetails, OAuth2User {}

이를 상속받으면 DB에 추가한 데이터까지 직렬화되어 저장된다.

이제 앱 1개, 웹 1개만 사용할 수 있도록 중복로그인을 막아보자.

  1. FindByIndexNameSessionRepository: SessionRepository에 지정된 인덱스 이름과 인덱스 값으로 세션을 찾을 수 있도록 하는 인터페이스
  2. SessionRepository: 세션을 관리하기 위한 저장소 인터페이스

우선 spring-session-jdbc 에서 제공하는 FindByIndexNameSessionRepositorySessionRepository를 사용해야 한다.

그리고 처리하는 단계를 설명하자면

  1. FindByIndexNameSessionRepository 를 통해 사용자 이메일에 해당하는 세션을 모두 가져온다.
  2. 세션에서 사용자 인증 객체를 추출한다.
  3. 인증 객체에서 어느 플랫폼(앱 or 웹) 에서 로그인했는지 추출한다.
  4. 현재 로그인한 플랫폼의 경로는 알고 있으므로 인증 객체에서 추출한 플랫폼과 현재 플랫폼이 같다면 중복 로그인이므로 SessionRepository 를 사용해서 이전 세션을 삭제한다.

다음과 같이 처리할 수 있게 된다.

처리하는 최종 코드

findByIndexNameSessionRepository.findByPrincipalName(email) 를 통해 사용자의 이메일에 해당하는 세션을 모두 가져오고 세션을 순회하면서 인증 객체를 추출하고 같은 플랫폼 경로인지 비교하여 같다면 세션을 삭제하는 식으로 구현하였다.

extractPrincipalDetails(session) 은 인증 객체를 추출하는 것으로 세션 속성에 "SPRING_SECURITY_CONTEXT" 로 객체를 추출할 수 있다.
인증 객체 추출에 대한 설명은 위 이미지를 보면 쉽게 파악할 수 있을 것이다.

그리고 이전 글에서 설명했지만 익명 객체는 세션 속성이 "SPRING_SECURITY_SAVED_REQUEST" 이므로 참고하길 바란다.

참조

https://docs.spring.io/spring-session/reference/guides/boot-findbyusername.html

profile
백엔드 희망자

0개의 댓글

관련 채용 정보