-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathCustomOAuth2UserService.java
More file actions
178 lines (145 loc) · 5.76 KB
/
CustomOAuth2UserService.java
File metadata and controls
178 lines (145 loc) · 5.76 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
package com.example.oauth2.security;
import com.example.oauth2.entity.User;
import com.example.oauth2.repository.UserRepository;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.oauth2.client.userinfo.DefaultOAuth2UserService;
import org.springframework.security.oauth2.client.userinfo.OAuth2UserRequest;
import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
import org.springframework.security.oauth2.core.user.OAuth2User;
import org.springframework.stereotype.Service;
import java.util.Map;
@Slf4j
@Service
@RequiredArgsConstructor
public class CustomOAuth2UserService extends DefaultOAuth2UserService {
private final UserRepository userRepository;
@Override
public OAuth2User loadUser(OAuth2UserRequest userRequest) throws OAuth2AuthenticationException {
OAuth2User oAuth2User = super.loadUser(userRequest);
try {
return processOAuth2User(userRequest, oAuth2User);
} catch (Exception ex) {
log.error("OAuth2 인증 처리 중 오류 발생", ex);
throw new OAuth2AuthenticationException(ex.getMessage());
}
}
private OAuth2User processOAuth2User(OAuth2UserRequest userRequest, OAuth2User oAuth2User) {
String registrationId = userRequest.getClientRegistration().getRegistrationId();
OAuth2UserInfo userInfo = OAuth2UserInfoFactory.getOAuth2UserInfo(registrationId, oAuth2User.getAttributes());
if (userInfo.getEmail() == null || userInfo.getEmail().isEmpty()) {
throw new OAuth2AuthenticationException("OAuth2 제공자로부터 이메일을 찾을 수 없습니다.");
}
User user = userRepository.findByEmail(userInfo.getEmail())
.map(existingUser -> updateExistingUser(existingUser, userInfo))
.orElse(registerNewUser(userRequest, userInfo));
return CustomOAuth2User.create(user, oAuth2User.getAttributes());
}
private User registerNewUser(OAuth2UserRequest userRequest, OAuth2UserInfo userInfo) {
User user = User.builder()
.name(userInfo.getName())
.email(userInfo.getEmail())
.picture(userInfo.getImageUrl())
.provider(User.SocialProvider.valueOf(
userRequest.getClientRegistration().getRegistrationId().toUpperCase()))
.providerId(userInfo.getId())
.role(User.Role.USER)
.build();
return userRepository.save(user);
}
private User updateExistingUser(User existingUser, OAuth2UserInfo userInfo) {
User updatedUser = existingUser.update(userInfo.getName(), userInfo.getImageUrl());
return userRepository.save(updatedUser);
}
}
// OAuth2UserInfo 인터페이스
interface OAuth2UserInfo {
String getId();
String getName();
String getEmail();
String getImageUrl();
}
// Google OAuth2UserInfo 구현
class GoogleOAuth2UserInfo implements OAuth2UserInfo {
private final Map<String, Object> attributes;
public GoogleOAuth2UserInfo(Map<String, Object> attributes) {
this.attributes = attributes;
}
@Override
public String getId() {
return (String) attributes.get("sub");
}
@Override
public String getName() {
return (String) attributes.get("name");
}
@Override
public String getEmail() {
return (String) attributes.get("email");
}
@Override
public String getImageUrl() {
return (String) attributes.get("picture");
}
}
// Kakao OAuth2UserInfo 구현
class KakaoOAuth2UserInfo implements OAuth2UserInfo {
private final Map<String, Object> attributes;
private final Map<String, Object> kakaoAccount;
private final Map<String, Object> profile;
public KakaoOAuth2UserInfo(Map<String, Object> attributes) {
this.attributes = attributes;
this.kakaoAccount = (Map<String, Object>) attributes.get("kakao_account");
this.profile = (Map<String, Object>) kakaoAccount.get("profile");
}
@Override
public String getId() {
return String.valueOf(attributes.get("id"));
}
@Override
public String getName() {
return (String) profile.get("nickname");
}
@Override
public String getEmail() {
return (String) kakaoAccount.get("email");
}
@Override
public String getImageUrl() {
return (String) profile.get("profile_image_url");
}
}
// Naver OAuth2UserInfo 구현
class NaverOAuth2UserInfo implements OAuth2UserInfo {
private final Map<String, Object> attributes;
public NaverOAuth2UserInfo(Map<String, Object> attributes) {
this.attributes = (Map<String, Object>) attributes.get("response");
}
@Override
public String getId() {
return (String) attributes.get("id");
}
@Override
public String getName() {
return (String) attributes.get("name");
}
@Override
public String getEmail() {
return (String) attributes.get("email");
}
@Override
public String getImageUrl() {
return (String) attributes.get("profile_image");
}
}
// Factory 클래스
class OAuth2UserInfoFactory {
public static OAuth2UserInfo getOAuth2UserInfo(String registrationId, Map<String, Object> attributes) {
return switch (registrationId.toLowerCase()) {
case "google" -> new GoogleOAuth2UserInfo(attributes);
case "kakao" -> new KakaoOAuth2UserInfo(attributes);
case "naver" -> new NaverOAuth2UserInfo(attributes);
default -> throw new OAuth2AuthenticationException("지원하지 않는 OAuth2 제공자입니다: " + registrationId);
};
}
}