https://qkrqkrrlrl.tistory.com/161
확장성이 좋은 oauth 코드로 리팩토링하기
https://qkrqkrrlrl.tistory.com/160 spring-oauth-client 라이브러리의 동작 흐름 정리해당 지식은 혼자 디버깅과 gpt, 블로그를 교차 검증 하면서 얻은 정보입니다. 틀린 내용이 있을 수 있습니다. 소셜 로그
qkrqkrrlrl.tistory.com
이전 게시글에서 oauth 코드를 리팩토링 하면서 다양한 소셜 환경을 빠르게 추가할 수 있도록 리팩토링을 진행했다.
그러니 한번 naver를 추가해 보면서 얼마나 쉽게 추가할 수 있는지 체감해 보고 수정해보려고 한다.
naver
우선 네이버 개발자 센터로 가서 애플리케이션을 등록한다.
https://developers.naver.com/apps/#/register
애플리케이션 - NAVER Developers
developers.naver.com
서비스에는 이메일과 별명만 필요하기에 체크
우선 localhost에서 테스트를 진행하기 때문에 이렇게 추가한다.
네이버에서 callback url은 기존의 redirect url을 의미하는 것.
이제 yml을 추가해야 한다. 기존의 kakao랑 비슷하다.
naver를 쓰기 위해서 인증 서버 url, 토큰 url, 유저 정보 접근 url 이렇게 3개가 필요하다. 네이버 공식문서를 보면 잘 나와있다.
일단 카카오 yml을 그대로 훔쳐서 부분만 변경시켜봤다.
provider:
naver:
authorization-uri: https://nid.naver.com/oauth2.0/authorize
token-uri: https://nid.naver.com/oauth2.0/token
user-info-uri: https://openapi.naver.com/v1/nid/me
user-name-attribute: id
registration:
naver:
client-id: id키
client-secret: 비밀키
client-authentication-method: client_secret_post
redirect-uri: http://localhost:8080/login/oauth2/code/naver
authorization-grant-type: authorization_code
client-name: naver
scope:
- account_email
- profile_nickname
위 yml을 사용해서 디버그를 통해 loadUser 서비스에 일단 찍히는 걸 확인해 봤다.
그러나 아래와 같은 에러가 발생했다.
'user-name-attribute: id'이 부분을 카카오 코드 그대로 가져왔더니 네이버에서는 인식을 못하는 모양이다.
네이버에서 제공하는 사용자 프로필 조회 정보는 아래처럼 JSON으로 반환을 해준다.
그래서 네이버를 사용할 때는 resultcode를 통해 구분하도록 했다.
user-name-attribute: resultcode
받아오는 attributes는 아래와 같다.
여기에 맞게 NaverUserInfo를 바꿔주면 된다.
기존의 kakao에서 사용했던 UserInfo를 그대로 사용했더니 문제가 발생. 아래의 코드가 그 코드이다.
package com.park.restapi.util.oauth.userinfo;
import com.park.restapi.util.oauth.RegistrationId;
import java.util.Map;
public class NaverUserInfo implements OAuth2UserInfo {
private Map<String, Object> attributes;
private RegistrationId registrationId;
public NaverUserInfo(Map<String, Object> attributes, RegistrationId registrationId) {
this.attributes = attributes;
this.registrationId = registrationId;
}
@Override
public String getProviderId() {
return String.valueOf(attributes.get("id"));
}
@Override
public String getProvider() {
return "naver";
}
@Override
public RegistrationId getRegistrationId() {
return registrationId;
}
@Override
public String getEmail() {
return (String) ((Map) attributes.get("naver_account")).get("email");
}
@Override
public String getNickname() {
Map<String, Object> kakaoAccount = (Map<String, Object>) attributes.get("naver_account");
Map<String, Object> profile = (Map<String, Object>) kakaoAccount.get("profile");
return (String) profile.get("nickname");
}
}
그래서 naver에서 제공하는 attributes에 맞게 코드를 변경.
package com.park.restapi.util.oauth.userinfo;
import com.park.restapi.domain.member.entity.SocialType;
import com.park.restapi.util.oauth.RegistrationId;
import java.util.Map;
public class NaverUserInfo implements OAuth2UserInfo {
private Map<String, Object> attributes;
private RegistrationId registrationId;
public NaverUserInfo(Map<String, Object> attributes, RegistrationId registrationId) {
this.attributes = attributes;
this.registrationId = registrationId;
}
@Override
public String getProviderId() {
return String.valueOf(((Map) attributes.get("response")).get("id"));
}
@Override
public SocialType getProvider() {
return SocialType.NAVER;
}
@Override
public RegistrationId getRegistrationId() {
return registrationId;
}
@Override
public String getEmail() {
return String.valueOf(((Map) attributes.get("response")).get("email"));
}
@Override
public String getNickname() {
return String.valueOf(((Map) attributes.get("response")).get("nickname"));
}
}
또 하면서 한 가지 문제가 발생했었다.
현재 db의 email은 유니크로 설정되어 있는데, 다른 소셜에서 같은 이메일을 가지는 경우가 발생한다.
ex) 카카오 - test@naver.com, 네이버 - test@naver.com
위의 경우 소셜 타입으로 구분을 진행해야 한다.
그래서 아래처럼 타입을 비교해서 이미 동일한 이메일이 있는지를 판단하도록 했다.
// 동일한 소셜인지 판단
if (!member.getSocialType().equals(oAuth2UserInfo.getProvider())) {
OAuth2Error error = new OAuth2Error(DIFF_SOCIAL_TYPE, member.getEmail() + " 유저가 로그인 시도를 진행했습니다.(다른 소셜 타입)",
null);
throw new OAuth2AuthenticationException(error);
}
이후 로직들은 successHandler에서 처리하면 소셜 로그인은 성공적으로 된다.
새롭게 회원가입이 추가된 것을 정상적으로 확인할 수 있다.
네이버의 경우 뭐 서비스 등록을 해야 실제 배포에서 사용할 수 있어서 일단 검수 신청을 넣을 예정이다.
확실히 UserInfo 인터페이스를 통해 기능을 추상화하고, 커스텀 UserInfo를 생성해서 사용하니 빠르게 소셜을 추가할 수 있다는 생각이 들었다.
'프로젝트 > RESTAPI 추천 서비스' 카테고리의 다른 글
확장성이 좋은 oauth 코드로 리팩토링하기 (0) | 2024.06.27 |
---|---|
도커 허브를 추가하여 이미지 백업을 구성하기. (0) | 2024.06.23 |
배포를 위해 진행했던 도커와 젠킨스 정리 (0) | 2024.06.21 |
서비스 내에서 발생하는 쿼리를 분석하고 개선하기 (0) | 2024.06.12 |