개발[프로젝트]/쿠스토랑

웹/앱 API 통합서버 소셜연동 로그인 구현부터 수정까지 (로그인1탄)

wcwdfu 2024. 9. 7. 16:48

웹/앱 API 통합서버 소셜연동 로그인 구현부터 수정까지 (로그인1탄)


 

기존에 '웹'서비스 에서는 띵운씨가 세션 기반 네이버 로그인을 구현한 상태였고, 앱 부분에 있어서는 로그인을 내가 한번 구현을 해보고 싶어서 내가 해보겠다고 말한 후 구현을 하게 되었다 .

 그랬다 ... 이거 처음하면 쉬운게 아니다. 라는 도전정신 가득 자극하는 멘트를 듣고 호기롭게 자신만만하게 내가 하겠다고 한 후, 공부해야할 부분이 많다는걸 뒤늦게 깨닫게 되었다 ...

(+ 기존에 웹/앱 서버 프로젝트를 따로따로 생성해서 하다가 하나로 통합하게 되면서 Security Config등과 같은 설정을 어떻게 해줘야 할지와 같은 부분에 대한 고민이 첨가되면서 충분히 어려운 내용이 더 어려워지게 되었다..😱😭)

 

- 기본적인 개발자 페이지나 유저 블로그들 에선 안드로이드 기반이니 ios니 api니 등등과 관련해서 단편적인 글은 차고 넘쳤지만, 앱 클라이언트 & 스프링부트 백엔드 서버를 통칭해서 전체적인 로그인 로직을 어떻게 구현해야 하는지 까지에 대해 디테일하게 설명한 블로그글을 나는 찾지 못한것 같다.

 

그래서 쿠스토랑의 웹/앱API 통합 서버의 로그인 로직 구현에 대한 이야기를 이번 포스트에서 다뤄보고자 한다.

※(네이버 개발자 페이지와 개발자Q&A페이지, 구글에서 검색된 십수개(수십개x)정도의 블로그를 참고했다)

※(일방적인 로그인 구현이나 jwt토큰이 뭐니 OAuth2.0은 뭐니 등등과 같이 인터넷에 차고 넘치는 정보들은 굳이 쓰지 않겠다. 왜냐면 말그대로 인터넷에 차고 넘치기 때문에 궁금하다면 인터넷에 검색해보길 바란다)

※(간단하게 적으면, 앱 로그인에서는 jwt토큰을 이용한다. 그 이유는 HTTP는 Stateless한 특성을 갖기 때문이다. OAuth2.0은 제3자의 서비스가 우리 서비스의 회원 인증 과정을 처리해주는 방식이다)


사고의 흐름은 절대 이렇지 않았지만, 정돈된 관점에서 우선 결정해야할 부분들과 공부해야할 부분들은 다음과 같았다.

1. 소셜 로그인 서버에서 자체적으로 발행해주는 jwt 토큰을 사용하는 방법.

2. 스프링부트 백엔드 서버에서 자체적으로 jwt토큰을 발행하여 사용하는 방법.

 

이 결론이 나기에는 앱 클라이언트+백엔드가 로그인을 어떤식으로 같이 처리해줘야 하는지 큰 그림이 필요한데, 다행히도 카카오 로그인 개발자 Q&A 페이지에서 대략적으로나마 확인해볼 수 있었다.

(참고 : https://devtalk.kakao.com/t/topic/134310/7)

 

그렇게 방식은 다음과 같다. (안드로이드 기준으로 설명하나 ios도 유사할것으로 추측된다)

1. 앱 클라이언트에서 네이버와 교신을 일임하고 백엔드에는 데이터만 넘기는 방식(백엔드에서 네이버 액세스 토큰을 사용하지 않을때)

2. 앱 클라이언트에서 네이버 로그인 후, 액세스 토큰을 백엔드에 전달하여 실제 데이터 교신은 백엔드에서 처리하는 방식.(rest-api로 할 경우 다소(?) 복잡한 로그인 과정이 앱sdk를 이용하면 매우 간편하게 provider_user_id와 네이버에서 자체 발행해주는 access_token을 가져올 수 있다)

3. REST-API방식을 사용하여 인앱브라우저로 인가코드 요청 부터 모두 백엔드에 일임하거나 인가코드 요청까지만 앱내 인앱브라우저에서 하고 리다이렉트URI를 백엔드로 설정하여 이후 백엔드에 일임하는 방식(즉 웹뷰를 사용해서 웹페이지를 모바일로 띄우고 모든 로그인 처리 로직은 백엔드에서 처리하는 것 같다)

 

위 글만 봐서도 깨끗하게 이해가 되지 않을 수 있다. 나도 그랬다.

그래서 결론부터 말하면 쿠스토랑의 api로그인은,

앱 클라이언트에서는 provider, provider_user_id와 네이버에서 발행해준 access_token 을 백엔드로 넘겨준다.

※(provider : 네이버, 카카오, 구글과 같이 로그인 서비스 제공자

provider_id : 서비스 제공자에서 유저마다 고유한 값으로 부여되는 유저 식별을 위한 값

provider도 같이 넘겨주는 이유는 원래 통합 로그인 기능 구현을 위해 카카오까지 추가하려고 했으나, 해당 기능 구현을 하기 위해서는 유저의 핸드폰 번호와 같이 중복되지 않는 고유한 값이 필요하다는게 현제 내가 내린 필수적인 결론인데,(그렇지 않으면 로직이 매우 복잡해짐) 우리 서비스는 이메일만 필수로 받고 있고, 핸드폰 번호급에 맞먹는 유니크한 값이 아니기에 네이버만 하게 되었다.

뿐만 아니라 각 제공자마다 로그인 로직 과정이 조금은 달라서 제공자마다 내부 로직을 다르게 처리해주기 위해 통상적으로 provider 값까지 같이 받는듯 하다)

 

※(처음에는 provider, provider_user_id만 받으려고 했으나, 웹 서버에서 user_builder를 통해 이메일 값까지 넣어줘서 회원가입 로직을 처리하고 있었기 때문에 유저 정보에 접근하기 위해서는 네이버에서 자체발행한 access_token이 필요했고 따라서 이 토큰까지 받기로 하였다.

그렇지 않을 경우 모바일에 먼저 로그인한 후, 웹에 로그인 하는 경우에 대해서 추가적인 로직이 필요했다(모바일을 통해 회원가입이 된 유저테이블에서 email 필드가 공란이기 때문))

※(백엔드 2년 현직에 계시다 ios로 전향하시는 팀원분이 계셔서 로그인 로직처리관련 조언을 여쭤봤었는데 user_id따로 생성하고 provider,provider_id는 한번 정규화해서 외래키로 묶어두면 나중에 소셜로그인 연동하기 편하다는 얘기를 해주셨다. 실제로 알아본 결과 DB에서 각각 테이블을 따로 만들어서 외래키를 통해 서로 관계를 맺는식으로 하는 것 같다. 그런데 앞서 말한바 다른 소셜 계정으로 로그인한 유저들을 통합시키기 위해서는 핸드폰 번호와 같이 유니크한 값이 필수적이라고 현재는 생각되어서 통합 로그인 구현은 제외하게 되었다) 

 

백엔드 서버에서는 

 

- 아직 작성중 -

- 전반적인 개선 작업 진행 후에 마저 작성하겠습니다. -

 

로그인된 유저 or (특정 권한이 있는 유저) 가 호출가능한 API를 설정하기위한 두가지 방법

 

메소드 수준 접근 제어 (@PreAuthorize):

메소드별로 다른 권한이 필요한 경우 유용(ex 어드민 유저, 일반 유저 등등.)

접근 제어 조건을 메소드에 직접 명시하여 코드 가독성을 높이고 싶을 때 사용

 

URL 패턴 기반 접근 제어 (Spring Security 설정 클래스에서 설정):

전역적으로 일관된 접근 제어가 필요한 경우 유용

중앙화된 접근 제어 설정을 선호할 때 사용