GPT 요약

My-Books 프로젝트에서는 Spring Gateway를 활용해 URL 기반 라우팅과 권한별 필터로 인가 로직을 설계했으나, 코드 중복과 비효율 문제가 발생했습니다.
SonarQube 피드백을 기반으로 중복 코드 문제를 해결하기 위해 유저와 어드민 필터를 통합하여 AuthFilter로 최적화했습니다.
사용자 상태 검토와 권한 검증을 효율적으로 처리하면서도 유지보수성과 확장성을 확보한 인가 시스템을 완성했습니다.

My-Books 프로젝트에서의 경험을 다룬 글입니다.

My-Books 프로젝트에서는 인증/인가 시스템 설계가 사용자 경험과 서비스 성능에 직결된다는 점을 알게 되었습니다.
이번 글에서는 Spring Gateway를 활용해 인가 로직을 최적화한 과정을 공유합니다.

초기 설계 - 단순 URL 기반 라우팅

처음에는 인증 서버와 백엔드 서버의 URL을 기반으로 라우팅을 구현했습니다.

  • 인증 서버: /auth/**
  • 백엔드 서버: /api/**

이 방식은 기본적인 요청 분리는 가능했지만, 모든 요청에 대해 인가 처리가 일어나는 비효율적인 구조였습니다.

이는 서비스 성능에 부정적인 영향을 끼쳤고, 이를 개선하기 위해 권한별 라우팅을 도입하기로 했습니다.

인가 처리 - 권한별 요청 구분

Spring Gateway의 RouteLocator를 활용해 요청을 권한별로 분리했습니다

  • 권한이 필요 없는 요청: /api/** , /auth/**
  • 유저 권한이 필요한 요청: /api/member/**
  • 어드민 권한이 필요한 요청: /api/admin/**

이제 권한이 필요 없는 요청은 인가 로직을 생략할 수 있어, 불필요한 리소스 낭비를 줄일 수 있었습니다.
또한 권한별 인가처리 세분화를 위해 유저 필터와 어드민 필터를 각각 구현했습니다.

  • 어드민 필터
    • 어드민 권한 확인.
    • 토큰의 유효성, 만료 여부, 조작 가능성 검토.
    • 요청 URL을 백엔드 서버의 REST API 형식에 맞게 변환.

  • 유저 필터
    • 유저 권한 확인.
    • 토큰의 유효성, 만료 여부, 조작 가능성 검토.
    • 요청 URL을 백엔드 서버의 REST API 형식에 맞게 변환.

다음과 같이 백엔드 API URL을 설정하는것도 생각해봤지만

  • /api/admin/**
  • /api/member/**

REST API형식에 어긋난다 생각하였기에 Gateway Filter에서 URL형식을 변경하는 방식을 선택했습니다.
또한 권한 계층을 두어 어드민 권한을 갖고 있을 시 모든 유저 기능을 사용 가능하게 구현하였습니다.

유저 상태 검토 - 왜 필요했을까?

권한에 따라 요청을 분리하고 인가 로직을 적용하던 중, 사용자 권한 외에도 사용자의 상태에 대해서도 고민하게 됐습니다.

이런 경험이 있지 않은가요?
오랜만에 사이트에 접속해 로그인을 하니 휴면계정으로 보호되어있다거나.. 로그인 시도가 계속시도되어 계정이 잠겼다던가..

저 또한 이런 경험이 있었기에 권한 뿐 아니라 상태에 대해서도 검증이 필요하다 생각했으며 이를 위해 유저 상태 검토 로직을 필터에 추가했습니다.

adminAuthFilter
userAuthFilter

그런데 Filter를 완성하고 나니 다음과 같은 피드백을 받게됩니다.

Q: SonarQube보니까 코드 중복도가 엄청 높던데 이거 통합하면 안되나요?

A: 역할이 다르기 때문에 분리해놓은 것이라 통합할 생각 없는데요?

그런데... 정말 그런가요??

중복되는 로직 개선 - 필터 통합

초기 설계에서는 userAuthFilteradminAuthFilter를 분리한 이유가 있었습니다.
권한별로 역할을 분리해두면 코드가 명확해지고, 확장성을 유지할 수 있다고 생각했기 때문입니다.

하지만, SonarQube를 활용해 코드 중복도를 분석한 결과 두 필터 간 중복 코드가 상당히 많았고, 이로 인해 코드 품질이 저하된다는 피드백을 받았습니다.

필터를 통합하는건 어렵진 않았습니다. 하지만 , "서로 역할이 달라보이는데 중복이 많다는 이유로 통합해야할까?" 라는 고민에 빠졌습니다.

역할별로 타입을 나누어 구현하는 가장 큰 이유는 확장성과 유지 보수성에 있다고 생각합니다.
하나의 객체가 다양한 역할을 수행하면 코드가 복잡해지고 확장성이 떨어지니까요, 그런데 이 경우는 어떤가요?

  • "인가 처리 로직이 자주 변경될 가능성이 있을까?"
  • "유저나 어드민 외에 새로운 권한이 추가될 가능성이 있을까?"
  • "활성, 잠금, 휴면 외에 추가적인 상태가 필요한 시나리오가 있을까?"

이 질문들을 깊이 고민해본 결과, 인가 처리 로직이 자주 변경될 가능성이 낮으며, 새로운 권한이나 상태가 추가될 가능성 또한 희박하다고 판단했습니다.

따라서, 유저와 어드민 필터를 하나의 필터로 통합해도 충분히 안정적이고 효율적인 구조를 유지할 수 있다는 결론에 도달했습니다.

그렇게 통합된 AuthFilter 코드입니다.

항상 느끼는 것이지만 여러 사람의 의견을 듣고 그 의견들을 깊이 고민하는 과정이 좋은 결과물을 만드는 것 같습니다.
이렇게 Gateway 인가 로직을 최적화하는 여정은 마무리됩니다.

같이 보시면 좋은 발표 영상입니다.

+ Recent posts