241210 소셜 로그인 이해하기

물고기가자라면어그로·2024년 12월 10일
3

사실 소셜 로그인은 연속으로 인증인가 파트를 맡은 내게 꼭 도전해보고 싶은 과제였다. 그러나 handler interceptor와 review 기능 구현을 맡아서 하다보니 시간이 생각보다 많이 소요됐다. 짧은 시간밖에 남지 않았지만 하다보니 오기도 생기고 어떻게든 조금이라도 구현해보고 싶어서 밤을 새어가며 공부했다.

네이버는 소셜 로그인 기능을 이용하기 위해 승인을 받는 과정이 좀 긴 것 같아서 일정이 촉박한 나는 카카오 소셜 로그인을 사용하기로 결정했다.

소셜 로그인은 JWT 로그인 방식과 결이 비슷한데 세션을 사용하는 것과는 달리 token을 이용하게 된다.

소셜 로그인 과정


출처 : kakao developers

소셜 로그인은 프론트와 백엔드가 밀접하게 연계되어있다는 느낌이 강했는데 카카오에서 제공하는 것들이 실제 프론트개발이 된 url 폼이 많아서 그랬던 것 같다.

우선 내가 이해한 소셜 로그인 과정은 이렇다.

0. 카카오에 서비스 등록 및 설정

우선 카카오에서 사용자 클라이언트(개발자)에게 api key를 부여하고 개발자는 redirect uri를 카카오에 등록해놓는다.

1. 인가코드 발급

rest key와 uri가 담긴 uri을 프론트에서 <카카오로 로그인하기> 와 같은 버튼 등에 연결
-> 로그인을 할 수 있는 창으로 redirect

로그인창이 뜰 수 있게 해주는 uri (인증 uri)

https://kauth.kakao.com/oauth/authorize?client_id={발급받은 api_key}&redirect_uri={등록한 redirect uri} &response_type=code

그냥 입력하면 간편로그인이 뜨고 뒤에 &prompt=login을 입력하면 직접 입력해서 로그인하는 창이 default로 뜬다.

그럼 이런 화면으로 연결되고 로그인을 해서 인증이 완료되면 다음과 같은 화면으로 자동으로 redirect되어 인가가 요청된다.

처음에 이것에 동의하면 카카오서버가 인가 코드를 발급한다.

2. 액세스토큰 발급받기

위에서 발급받은 인가코드는 우리가 설정했던 redirect uri의 뒤에 파라미터로 붙게 된다.

http://localhost:8080/api/users/kakao/loginRedirect?code={인가코드}

사용자는 그렇게 인가코드가 붙은 uri로 자동 리다이렉트된다.
(위의 인가코드 발급에서 한 번에 이어짐.)
-> 액세스 토큰을 발급받아 서비스를 이용할 수 있게 됨

이 때의 redirect uri의 메서드, 즉 액세스 토큰을 발급하는 메서드는 백엔드에서 구현한다.

3. 유저 정보 저장과 캐싱

첫 로그인을 할 때 (인가를 받고) 카카오 서버에서 유저의 정보를 받아 백엔드에서 회원정보를 db에 저장한다. (회원가입이 된 것이므로)
회원정보를 불러올 때는 카카오에서 제공하는 url로 연결시켜 받아올 수 있다.

https://kapi.kakao.com/v2/user/me

회원 정보가 쓰일 때마다 카카오서버에 요청해서 정보를 불러올 수 있지만, 그렇게 하기보다 꼭 실시간의 정보를 불러오는 것이 필요한 게 아니라면 db에 저장된 회원 정보를 사용하는 것이 의존성을 낮추는 데에 좋다.

Access Token & Refresh Token

여기서 발급받은 액세스 토큰은 액세스 토큰의 유효여부(존재여부or만료여부)로 로그인의 유효함을 검증하는 역할을 한다.

하지만 보안을 위해 Access Token의 유효기간은 짧은 편이다.
대신 처음에 함께 발급되는 Refresh Token 의 유효기간이 더 길어(1달~2달) 이 Refresh Token 으로 새로운 Access Token을 요청할 수 있다.

캐싱

그렇다면 발급되는 액세스 토큰이 로그인 여부만 검증한다면 로그인한 사람의 정보는 어떻게 저장할까?

답은 캐싱이다.

Access Token값을 key 값으로, 사용자의 정보를 캐시에 저장하는 것이다.

 @Cacheable(value = "캐시명", key = "#accessToken")
  public Long cacheKakaoUserIdWithEmail (String email, String accessToken) {
      User user = userRepository.findByEmailOrElseThrow(email);
      return user.getId();
  }

이런 식으로 @Cacheable 어노테이션을 사용해 return 값key 값과 함께 캐시에 저장할 수 있다.

이 때, @Cacheablevalue값은 캐시의 이름, key값은 액세스 토큰 값으로 지정하는데 이 이름이 매개변수에 담기는 accessToken의 변수명과 같아야한다.

캐시에서 값을 받아올 때는 cacheManager를 사용한다. (의존성주입필요)
cacheManager.getCache(캐시명)를 통해 현재 가진 Cache를 불러오고
캐시.get(key값,반환데이터 타입) 을 통해 저장된 사용자정보를 가져올 수 있다.

Cache kakaoUserId = cacheManager.getCache("KakaoUserId");
Long userId = kakaoUserId.get(Authorization.substring(7), Long.class);

위의 Authorization은 @RequestHeader로 담긴 액세스 토큰 값이다.
보통 Bearer 액세스토큰값 으로 입력하기 때문에 앞의 Bearer(토큰 타입)을 제외하기 위해 .substring()을 사용하였다.

*Bearer 토큰 : 토큰을 소유한 사람에게 액세스 권한을 부여하는 일반적인 토큰 클래스

4. 로그아웃

로그아웃은 카카오에서 제공하는 로그아웃 url로 연결을 시켜 Access Token 과 Refresh Token을 함께 만료시킨다.

https://kapi.kakao.com/v1/user/logout

나는 이 때 캐시도 삭제될 수 있도록 서비스 영역의 로그아웃 메서드에 @CacheEvict 어노테이션을 사용해주었다.
@CacheEvictvaluekey@Cacheable과 동일하게 작동한다.
역시 매개변수로 accessToken 값을 받아줘야 쓸 수 있다. (컨트롤러 영역에서 헤더에서 .substring()으로 추출해서 넣어준다.)

@CacheEvict(value = "캐시명", key = "#accessToken")

이번 프로젝트에서의 구현한계 & 개선점

  원래 소셜로그인을 할 때, 다른 기능들에의 접근 인증인가를 해야하면 OAuth 2.0Spring Security 를 사용한다고 한다. 그러나 나는 이를 구현하는 과정에서 오류가 너무 많이 났고 이를 공부해서 해결할 시간이 충분하지 않다고 생각해서 handler Interceptor 에서 로그인 할 때 저장했던 캐시를 불러와 직접 확인하는 식으로 진행시켰다. OAuth 2.0 과 Spring Security를 이용해서 소셜로그인으로 로그인한 회원에 대해 인증인가를 진행하여 더 정교하고 안전하게 프로젝트를 보호하고 접근제어를 할 수 있을 것 같다.

  또한, 현재 비슷한 문제 때문에 로그인한 회원의 정보를 불러오는 방법이 세션이용자와 토큰+캐시 이용자가 달라 이를 구별해야하는 문제가 있었는데 시간이 너무 오래걸릴 것 같다는 생각이 들어 포기하게 되었다.
  현재 구현단계에서는 소셜로그인 사용자는 소셜 로그인 / 소셜 로그인 회원의 권한 설정 / 로그아웃 외에 다른 기능을 사용할 수 없는데 user 테이블에 로그인 방법(이메일, 카카오톡, 네이버 등)을 담을 수 있는 칼럼을 만들어서 저장하고 로직을 더 추가해서 앱의 다른 기능들까지 사용할 수 있도록 확장시킬 수 있을 것같다.

  어려웠지만 우리가 일상에서 흔히 접하는 소셜로그인을 부분적으로나마 구현할 수 있어서 굉장히 뿌듯했다. 다음에 시간이 더 주어진다면 완전하게 구현할 수 있지 않을까? 설계단계부터 잘 만져야할 부분 같다. 어쩌면 다음 프로젝트에는 가능할지도...

0개의 댓글

관련 채용 정보