Skip to content

Commit ee2781d

Browse files
authored
Fix/issue 172 oauth login (#174)
* [BE] edit CustomOAuth2UserService, UserOauthAccountRepository,TokenEncryptor * [BE] edit CustomOAuth2UserService, UserOauthAccountRepository,TokenEncryptor * [BE] edit CustomOAuth2UserService
1 parent ec2353d commit ee2781d

1 file changed

Lines changed: 43 additions & 29 deletions

File tree

backend/src/main/java/org/sejongisc/backend/common/auth/config/CustomOAuth2UserService.java

Lines changed: 43 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
import org.sejongisc.backend.user.dao.UserRepository;
1010
import org.sejongisc.backend.user.entity.Role;
1111
import org.sejongisc.backend.user.entity.User;
12-
import org.sejongisc.backend.user.service.UserServiceImpl;
1312
import org.springframework.security.core.authority.SimpleGrantedAuthority;
1413
import org.springframework.security.oauth2.client.userinfo.DefaultOAuth2UserService;
1514
import org.springframework.security.oauth2.client.userinfo.OAuth2UserRequest;
@@ -27,7 +26,8 @@
2726
@Service
2827
@RequiredArgsConstructor
2928
@Transactional
30-
public class CustomOAuth2UserService implements OAuth2UserService <OAuth2UserRequest, OAuth2User> {
29+
public class CustomOAuth2UserService implements OAuth2UserService<OAuth2UserRequest, OAuth2User> {
30+
3131
private final UserRepository userRepository;
3232
private final UserOauthAccountRepository oauthAccountRepository;
3333

@@ -71,6 +71,11 @@ public OAuth2User loadUser(OAuth2UserRequest req) throws OAuth2AuthenticationExc
7171

7272
AuthProvider authProvider = AuthProvider.from(provider);
7373

74+
// ✅ 선택지 A: email이 없으면 가상 이메일 생성 (User 생성용)
75+
if (email == null || email.isBlank()) {
76+
email = provider + "_" + providerUid + "@oauth.local";
77+
}
78+
7479
// 1) (provider, providerUid)로 먼저 찾는다 (기존 OAuth 로그인 사용자)
7580
Optional<UserOauthAccount> oauthLinkOpt =
7681
oauthAccountRepository.findByProviderAndProviderUid(authProvider, providerUid);
@@ -82,19 +87,15 @@ public OAuth2User loadUser(OAuth2UserRequest req) throws OAuth2AuthenticationExc
8287
} else {
8388
// 2) 링크가 없으면 email로 기존 로컬/회원가입 유저를 찾는다 (핵심!)
8489
Optional<User> userByEmailOpt = Optional.empty();
85-
if (email != null && !email.isBlank()) {
90+
if (!email.isBlank()) {
8691
userByEmailOpt = userRepository.findUserByEmail(email);
8792
}
8893

8994
if (userByEmailOpt.isPresent()) {
9095
// 3) 기존 유저가 있으면: 새 유저 만들지 말고 OAuth 링크만 추가
9196
user = userByEmailOpt.get();
9297

93-
// (선택) 이미 같은 provider로 링크가 있으면 중복 저장 방지
94-
// repository에 메서드 없으면 try/catch로 unique constraint에 맡겨도 됨
95-
boolean alreadyLinked = oauthAccountRepository
96-
.existsByProviderAndUser(authProvider, user);
97-
98+
boolean alreadyLinked = oauthAccountRepository.existsByProviderAndUser(authProvider, user);
9899
if (!alreadyLinked) {
99100
UserOauthAccount oauth = UserOauthAccount.builder()
100101
.user(user)
@@ -105,23 +106,40 @@ public OAuth2User loadUser(OAuth2UserRequest req) throws OAuth2AuthenticationExc
105106
}
106107

107108
} else {
108-
// 4) email로도 못 찾으면 신규 생성 + 링크
109-
User newUser = User.builder()
110-
.email(email) // null 가능성: DB 제약(NOT NULL/UNIQUE) 있으면 정책 필요
111-
.name(name)
112-
.role(Role.TEAM_MEMBER)
113-
.build();
114-
115-
User saved = userRepository.save(newUser);
116-
117-
UserOauthAccount oauth = UserOauthAccount.builder()
118-
.user(saved)
119-
.provider(authProvider)
120-
.providerUid(providerUid)
121-
.build();
122-
oauthAccountRepository.save(oauth);
123-
124-
user = saved;
109+
// 4) email로도 못 찾으면 신규 생성 + 링크 (경합 대비 try/catch)
110+
try {
111+
User newUser = User.builder()
112+
.email(email)
113+
.name(name)
114+
.role(Role.TEAM_MEMBER)
115+
.build();
116+
117+
User saved = userRepository.save(newUser);
118+
119+
UserOauthAccount oauth = UserOauthAccount.builder()
120+
.user(saved)
121+
.provider(authProvider)
122+
.providerUid(providerUid)
123+
.build();
124+
oauthAccountRepository.save(oauth);
125+
126+
user = saved;
127+
128+
} catch (org.springframework.dao.DataIntegrityViolationException e) {
129+
// 동시에 다른 트랜잭션이 같은 이메일 유저를 먼저 만들어버린 경우(UK 충돌)
130+
User existing = userRepository.findUserByEmail(email)
131+
.orElseThrow(() -> e);
132+
133+
if (!oauthAccountRepository.existsByProviderAndUser(authProvider, existing)) {
134+
UserOauthAccount oauth = UserOauthAccount.builder()
135+
.user(existing)
136+
.provider(authProvider)
137+
.providerUid(providerUid)
138+
.build();
139+
oauthAccountRepository.save(oauth);
140+
}
141+
user = existing;
142+
}
125143
}
126144
}
127145

@@ -133,13 +151,9 @@ public OAuth2User loadUser(OAuth2UserRequest req) throws OAuth2AuthenticationExc
133151
attributes.put("userId", user.getUserId());
134152

135153
return new DefaultOAuth2User(
136-
// 기존처럼 고정 ROLE 주고 싶으면 그대로 두고,
137-
// 권한을 user role 기반으로 주고 싶으면 아래 주석 라인으로 교체해도 됨
138154
List.of(new SimpleGrantedAuthority("ROLE_TEAM_MEMBER")),
139-
// List.of(new SimpleGrantedAuthority("ROLE_" + user.getRole().name())),
140155
attributes,
141156
"userId"
142157
);
143158
}
144-
145159
}

0 commit comments

Comments
 (0)