본문 바로가기

개발자로써./개발 하면서 했던 고민

간편 로그인 연동 개발 리뷰

간편 로그인(카카오, 네이버) 연동을 진행하면서 개발하면서 중점을 맞췄던 내용에 대한 리뷰를 해보고자 한다.

여기서는 카카오를 기준으로, 카카오를 예로 들어 설명을 진행하려고 한다.

배경 지식

https://developers.kakao.com/docs/latest/ko/kakaologin/rest-api

 

Kakao Developers

카카오 API를 활용하여 다양한 어플리케이션을 개발해보세요. 카카오 로그인, 메시지 보내기, 친구 API, 인공지능 API 등을 제공합니다.

developers.kakao.com

중점 사항

개발을 진행하면서 생각했던 중점사항은 크게 4가지였다.

  • OCP  - open closed principal ( 추상 메소드 팩토리 패턴, 전략 패턴 )
  • 유지보수, 낮은 결합도 ( Interface의존, folder 구조 )
  • 외부 API 의존성 낮추기, 모든 경우의 Exception 처리

OCP  - open closed principal ( 추상 메소드 팩토리 패턴, 전략 패턴 )

가장 고려 했던 부분은 기존에 소셜 로그인 방식말고 새로운 방식이 추가될 가능성이 있으니 변화에 열려 있어야 하는 것이였다.

그리고 인터페이스를 기반으로, 인터페이스를 사용함으로써 변화가 불필요하게 일어나지 않도록 폐쇄하는 것이였다.

 

그리고 그렇게 하기 위햐서 추상 메소드 팩토리 패턴과 전략 패턴을 사용하였다.

1) 의도 한 부분 - 최상위 Interface

  • 가장 공통이 되는 Method를 모아놓은 Interface를 만든다. 그리고 그 Interface를 상속하여 구현하도록 의도한다. -> Controller단에서 함수를 호출하기 위해 변화를 일으키게 하려면 Interface에 Method를 추가해야 하는데, 이는 상속하는 Class들에 대해 해당 함수를 구현해야 함을 의미한다. 이는 개발자가 실제로 내가 해야 하는 부분이 맞는가라는 생각을 하게 만들고 변화가 불필요하게 일어나지 않도록 굳게 폐쇄시킨다는 의미이다.
  • 이렇게 할시, Controller단에서는 DI를 통해 전략패턴을 의도할수 있고, 이를 상속한 Class들은 protected 접근 제어자를 사용해 내가 의도한 부분의 Method만 노출이 가능하게 한다. -> 즉 불필요한 메소드를 노출하지 않음으로써, 개발자의 실수를 방지하고 동시에 가독성을 올려 유지보수성을 향상시킨다.

2) 의도 한 부분 - Interface를 상속하는 abstract class

  • Interface에 선언한 공통적인 메소드들에 대한 구현이 이루어진다. -> 상위 Interface를 통하게 함으로써, Controller단에서는 DI를 할시 구현 클래스에 대한 의존성을 제거할수 있고 이는 역시 변화에 열려있는 코드를 만들게 한다.
  • 각 간편 연동 방식마다 다르게 구현되어야 하는 부분인 토큰을 얻는 메소드, 토큰을 통해 유저 정보를 얻는 메소드는 protected abstract으로 선언하여 상속한 하위 클래스들만 구현할수 있고, 구현을 강제하는 추상 메소드 팩토리 패턴을 사용하였다. -> 이렇게 함으로써, 다른 간편 연동 방식이 추가하여도 추상 클래스를 상속하여 상속받은 메소드만 구현하게 함으로써, 확장에 개방될수 있게 의도하였다.

3) 공통적인 메소드는 Utils 클래스를 만들어 빼두었고, 인증코드와 같은 변화하기 쉬운 항목도 enum을 만들어 관리 포인트를 한곳으로 모았다. 이건 너무 당연하게 해야 하는 것이다.

유지 보수, 낮은 결합도

1) 관리 포인트를 한곳으로 모으기 위해, folder를 추가하였다. 간편 로그인이지만 기존 Login Controller에 해당 내용을 추가하지 않았다.

대신에 Social Controller를 만들었고, Social folder를 만들어서 관련된 내용들은 해당 폴더안에 위치하도록 의도하였다.

2) 결합도는 '하나의 오브젝트가 변경이 일어날때에 관계를 맺고 있는 다른 오브젝트에게 변화를 요구하는 정도'라고 할수 있다. 

낮은 결합도란 결국, 하나의 변경이 발생할때에 마치 파문이 이는 것처럼 여타 모듈과 객체로 변경에 대한 요구가 전파되지 않는 상태를 말한다.

이는 최상위 Interface를 통해 해결하였다. Controller는 Interface를 변수로 가지고 있고 이는 최하위 KakaoSocialLnkgServiceImpl의 메소드가 추가되거나 변경되여도 영향을 받지 않는다는 의미이다. 간편 연동 구현 클래스와 Controller간에 결합도를 Interface를 사용하여서 낮추는 방식을 의도하였다.

외부 API 의존성 낮추기, 모든 경우의 Exception 처리

현재의 Architecture 구조

전형적인 구조이다. 내 고민은 어디서 소셜 API 서버와 연동 처리를 해야 할까 하는 부분이였다.

해당 부분에 대한 구체적인 생각을 얻고 싶어서 흐름과 Exception이 어떻게 발생하는지에 대한 그림을 그렸다.

1) 해당 로직을 살펴보았을때, Client Server단에서 위의 로직을 처리할시 BackEnd단에 소셜 유저정보 업데이트 API를 호출해야 하는데, 디비 업데이트과정에서 Exception 발생시 Exception에 대한 처리가 어렵다고 판단했다.

왜냐면,

Client Server -> 소셜 연동 해제 API 호출(소셜 서버에) -> 성공시 -> BackEnd 소셜 유저정보 업데이트 API 호출 -> 응답값 전달 의 구조로 흐르는데, BackEnd 소셜 유저정보 업데이트 API가 실패하게 된다면??? 이미 돌이킬수 없는 강이다...

소셜 서버는 유저에 대한 정보가 끊어졌는데, 내부 DB에는 연동되었다는 기록이 남는다. 

이 부분을 최대한 방지해야 한다고 생각했다.

 

How?

기존에 생각했던 구조는 다음과 같다.

여러가지 방법을 생각하였다.

Redis를 통해 상태값을 저장하는 방법, 그리고 밑에 말할 방법 등을 고민하였다.

 

결국 현재 상황에서 최적의 답은 BackEnd Server에서 @Transactional annotation으로 처리하는것이라 생각하였다.

수정한 로직은 다음과 같다.

문제점 분석

Client Server에서 소셜 API서버와 연동을 진행하고, 그 결과값을 가지고 BackEnd Server에 요청을 하기 때문에 의존성이 2가지 범주가 생긴다고 생각하였다.

즉, 위에서 발생하는 문제점은 두개의 서버에 요청을 나눠 보내고 그 두개의 서버에서 각각 트랜잭션을 실행하므로, 각각을 제어해야 하는데에서 오는 문제점이라고 생각했다.

그래서 제어해야 하는 외부 의존성을 내가 통제하지 못하는 소셜 API 서버 1가지로 제한하여 해결하고자 하였다.

 

해결

이렇게 했을시 간편 연동 해제 상황이라고 가정하자.

 

실패 상황

1) 통제할수 있는 범위인 BackEnd Server에서 DB와의 업데이트를 먼저 실행하고 실패시 Error Response를 호출한다.

2) BackEnd Server에서 DB업데이트 성공시, 소셜 API 서버에 간편 연동 해제 API를 호출한다. 해당 요청이 실패할시, @Transactional로 묶였기에, 전의 DB 업데이트까지 RollBack처리 된다.

3) 이후 실패 응답값을 Client단에 전송한다.

 

성공 상황

1) 통제할수 있는 범위인 BackEnd Server에서 DB와의 업데이트를 먼저 실행하고 소셜 API 서버에 간편 연동 해제 API를 호출한다.

2) 성공시, 성공값을 Client에 전송한다.

 

개선으로 인해 얻을수 있는 이점

  • 보안적인 이슈 : 방화벽에 인가된 정보만 허가함으로써, 보안적인 측면을 강화시킬수 있다.
  • 연동결과값에 따른 소셜 API 서버와 내부 DB의 데이터 원자성을 유지할수 있다.

위와 같은 방식으로 Back-End Server의 소셜 API서버 연동은 끝이 났다. ( 사실 Back-End에 만들수밖에 없었다. 업무 프로그램과도 연결되어 있어서)

 

실제적으로 호출되는 홈페이지 Client Server에서는 Spring Security가 제공해주는 OAuth2Filter를 사용하여서 해결하였다.

 

추가적으로 했던 고민들

https://ptrsr.tistory.com/274

 

Tocken 전송은 항상 옳은가 ?

사람들과 대화를 해보거나 물어보면 Tocken전송을 통한 인가(Jwt Tocken)에 대해서 보안적인 측면은 생각하지 않고 개발하시는 분들이 많은것 같다. 그렇다면 Tocken전송을 통한 인가는 항상 옳은가? w

ptrsr.tistory.com

'개발자로써. > 개발 하면서 했던 고민' 카테고리의 다른 글

결제 시스템 개선기  (0) 2022.08.27