Skip to content

Commit 58d9de5

Browse files
authored
Merge pull request #286 from Gongjakso/feat/naver-login
Feat: Naver login 구현
2 parents d473212 + f3a3c51 commit 58d9de5

File tree

6 files changed

+190
-2
lines changed

6 files changed

+190
-2
lines changed
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
package com.gongjakso.server.domain.member.enumerate;
22

33
public enum LoginType {
4-
GENERAL, KAKAO , GOOGLE
4+
GENERAL, KAKAO , GOOGLE, NAVER
55
}

src/main/java/com/gongjakso/server/domain/member/service/AuthService.java

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@
1414
import com.gongjakso.server.global.security.kakao.KakaoClient;
1515
import com.gongjakso.server.global.security.kakao.dto.KakaoProfile;
1616
import com.gongjakso.server.global.security.kakao.dto.KakaoToken;
17+
import com.gongjakso.server.global.security.naver.NaverClient;
18+
import com.gongjakso.server.global.security.naver.dto.NaverProfile;
19+
import com.gongjakso.server.global.security.naver.dto.NaverToken;
1720
import com.gongjakso.server.global.util.redis.RedisClient;
1821
import lombok.RequiredArgsConstructor;
1922
import org.springframework.stereotype.Service;
@@ -29,6 +32,7 @@ public class AuthService {
2932
private final RedisClient redisClient;
3033
private final TokenProvider tokenProvider;
3134
private final MemberRepository memberRepository;
35+
private final NaverClient naverClient;
3236

3337
@Transactional
3438
public LoginRes signIn(String code, String redirectUri, String type) {
@@ -39,7 +43,7 @@ public LoginRes signIn(String code, String redirectUri, String type) {
3943
Member member = switch (loginType) {
4044
case KAKAO -> kakaoMember(code, redirectUri);
4145
case GOOGLE -> googleMember(code, redirectUri);
42-
46+
case NAVER -> naverMember(code, redirectUri);
4347
default -> null;
4448
};
4549

@@ -103,6 +107,30 @@ private Member googleMember(String code, String redirectUri) {
103107
return member;
104108
}
105109

110+
private Member naverMember(String code, String redirectUri){
111+
// 네이버로 액세스 토큰 요청하기
112+
NaverToken naverAccessToken = naverClient.getNaverAccessToken(code, redirectUri);
113+
114+
// 네이버에 있는 사용자 정보 반환
115+
NaverProfile naverProfile = naverClient.getMemberInfo(naverAccessToken);
116+
117+
// 반환된 정보의 이메일 기반으로 사용자 테이블에서 계정 정보 조회 진행
118+
// 이메일 존재 시 로그인 , 존재하지 않을 경우 회원가입 진행
119+
Member member = memberRepository.findMemberByEmailAndDeletedAtIsNull(naverProfile.response().email()).orElse(null);
120+
121+
if(member == null) {
122+
Member newMember = Member.builder()
123+
.email(naverProfile.response().email())
124+
.name(naverProfile.response().name())
125+
.memberType("GENERAL")
126+
.loginType("NAVER")
127+
.build();
128+
129+
return memberRepository.save(newMember);
130+
}
131+
return member;
132+
}
133+
106134
public void signOut(String token, Member member) {
107135
// Validation
108136
String accessToken = token.substring(7);
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
package com.gongjakso.server.global.security.naver;
2+
3+
import com.fasterxml.jackson.databind.ObjectMapper;
4+
import com.gongjakso.server.global.security.naver.dto.NaverProfile;
5+
import com.gongjakso.server.global.security.naver.dto.NaverToken;
6+
import lombok.RequiredArgsConstructor;
7+
import lombok.extern.slf4j.Slf4j;
8+
import org.springframework.beans.factory.annotation.Value;
9+
import org.springframework.stereotype.Component;
10+
import org.springframework.util.LinkedMultiValueMap;
11+
import org.springframework.util.MultiValueMap;
12+
import org.springframework.web.reactive.function.BodyInserters;
13+
import org.springframework.web.reactive.function.client.WebClient;
14+
15+
@Slf4j
16+
@Component
17+
@RequiredArgsConstructor
18+
public class NaverClient {
19+
20+
@Value("${spring.security.oauth2.client.provider.naver.token-uri}")
21+
private String naverTokenUri;
22+
23+
@Value("${spring.security.oauth2.client.registration.naver.client-id}")
24+
private String naverClientId;
25+
26+
@Value("${spring.security.oauth2.client.registration.naver.authorization-grant-type}")
27+
private String naverGrantType;
28+
29+
@Value("${spring.security.oauth2.client.registration.naver.client-secret}")
30+
private String naverClientSecret;
31+
32+
@Value("${spring.security.oauth2.client.provider.naver.user-info-uri}")
33+
private String naverUserInfoUri;
34+
35+
@Value("${spring.security.oauth2.client.provider.naver.authorization-uri}")
36+
private String naverAuthorizationUri;
37+
38+
/**
39+
* 네이버 서버에 인가코드 기반으로 사용자의 토큰 정보를 조회하는 메소드
40+
* @param code - 네이버에서 발급해준 인가 코드
41+
* @return - 네이버에서 반환한 응답 토큰 객체
42+
*/
43+
public NaverToken getNaverAccessToken(String code, String redirectUri) {
44+
// 요청 보낼 객체 기본 생성
45+
WebClient webClient = WebClient.create(naverTokenUri);
46+
47+
//요청 본문
48+
MultiValueMap<String , String> params = new LinkedMultiValueMap<>();
49+
params.add("grant_type", naverGrantType);
50+
params.add("client_id", naverClientId);
51+
params.add("redirect_uri", redirectUri);
52+
params.add("code", code);
53+
params.add("client_secret", naverClientSecret);
54+
55+
// 요청 보내기 및 응답 수신
56+
String response = webClient.post()
57+
.uri(naverTokenUri)
58+
.header("Content-type", "application/x-www-form-urlencoded")
59+
.body(BodyInserters.fromFormData(params))
60+
.retrieve() // 데이터 받는 방식, 스프링에서는 exchange는 메모리 누수 가능성 때문에 retrieve 권장
61+
.bodyToMono(String.class) // (Mono는 단일 데이터, Flux는 복수 데이터)
62+
.block();// 비동기 방식의 데이터 수신
63+
64+
// 수신된 응답 Mapping
65+
ObjectMapper objectMapper = new ObjectMapper();
66+
NaverToken naverToken;
67+
try {
68+
naverToken = objectMapper.readValue(response, NaverToken.class);
69+
} catch (Exception e) {
70+
throw new RuntimeException(e);
71+
}
72+
73+
return naverToken;
74+
}
75+
76+
public NaverProfile getMemberInfo(NaverToken naverToken) {
77+
// 요청 기본 객체 생성
78+
WebClient webClient = WebClient.create(naverUserInfoUri);
79+
80+
// 요청 보내서 응답 받기
81+
String response = webClient.post()
82+
.uri(naverUserInfoUri)
83+
.header("Content-Type", "application/x-www-form-urlencoded;charset=utf-8")
84+
.header("Authorization", "Bearer " + naverToken.access_token())
85+
.retrieve()
86+
.bodyToMono(String.class)
87+
.block();
88+
89+
// 수신된 응답 Mapping
90+
ObjectMapper objectMapper = new ObjectMapper();
91+
NaverProfile naverProfile;
92+
try {
93+
naverProfile = objectMapper.readValue(response, NaverProfile.class);
94+
95+
} catch (Exception e) {
96+
throw new RuntimeException(e);
97+
}
98+
99+
return naverProfile;
100+
}
101+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package com.gongjakso.server.global.security.naver;
2+
3+
import lombok.RequiredArgsConstructor;
4+
import org.springframework.security.oauth2.client.userinfo.DefaultOAuth2UserService;
5+
import org.springframework.security.oauth2.client.userinfo.OAuth2UserRequest;
6+
import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
7+
import org.springframework.security.oauth2.core.user.OAuth2User;
8+
import org.springframework.stereotype.Service;
9+
10+
@Service
11+
@RequiredArgsConstructor
12+
public class NaverUserService extends DefaultOAuth2UserService {
13+
14+
@Override
15+
public OAuth2User loadUser(OAuth2UserRequest oAuth2UserRequest) throws OAuth2AuthenticationException {
16+
return null;
17+
}
18+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package com.gongjakso.server.global.security.naver.dto;
2+
3+
import lombok.Builder;
4+
5+
@Builder
6+
public record NaverProfile(
7+
String resultcode,
8+
String message,
9+
NaverProfileResponse response
10+
) {
11+
public record NaverProfileResponse(
12+
String id,
13+
String name,
14+
String nickname,
15+
String profile_image,
16+
String email,
17+
String age,
18+
String birthday,
19+
String gender,
20+
String mobile,
21+
String mobile_e164,
22+
String birthyear
23+
) {
24+
}
25+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package com.gongjakso.server.global.security.naver.dto;
2+
3+
import jakarta.validation.constraints.Null;
4+
import lombok.Builder;
5+
6+
@Builder
7+
public record NaverToken(
8+
String access_token,
9+
@Null
10+
String refresh_token,
11+
int expires_in,
12+
String token_type,
13+
String error,
14+
String error_description
15+
) {
16+
}

0 commit comments

Comments
 (0)