Skip to content

Commit cb5bad6

Browse files
committed
[feat] OAuth2 기반 구조 구축
1 parent 0270a11 commit cb5bad6

File tree

8 files changed

+278
-1
lines changed

8 files changed

+278
-1
lines changed

src/main/generated/com/back/domain/funding/entity/QFunding.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ public class QFunding extends EntityPathBase<Funding> {
2929

3030
public final NumberPath<Long> collectedAmount = createNumber("collectedAmount", Long.class);
3131

32+
public final ListPath<FundingCommunity, QFundingCommunity> communities = this.<FundingCommunity, QFundingCommunity>createList("communities", FundingCommunity.class, QFundingCommunity.class, PathInits.DIRECT2);
33+
3234
//inherited
3335
public final DateTimePath<java.time.LocalDateTime> createDate = _super.createDate;
3436

@@ -46,6 +48,8 @@ public class QFunding extends EntityPathBase<Funding> {
4648
//inherited
4749
public final DateTimePath<java.time.LocalDateTime> modifyDate = _super.modifyDate;
4850

51+
public final ListPath<FundingNews, QFundingNews> news = this.<FundingNews, QFundingNews>createList("news", FundingNews.class, QFundingNews.class, PathInits.DIRECT2);
52+
4953
public final ListPath<FundingOption, QFundingOption> options = this.<FundingOption, QFundingOption>createList("options", FundingOption.class, QFundingOption.class, PathInits.DIRECT2);
5054

5155
public final NumberPath<Integer> participantCount = createNumber("participantCount", Integer.class);

src/main/java/com/back/domain/user/entity/User.java

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,43 @@ public void changeGrade(Grade newGrade) {
163163
this.grade = newGrade;
164164
}
165165

166+
/**
167+
* OAuth 관련 메서드들
168+
*/
169+
170+
// 정적 팩토리 메서드 - OAuth 회원가입
171+
public static User createOAuthUser(String email, String name, Provider provider, String providerId) {
172+
User user = new User();
173+
user.email = email;
174+
user.name = name;
175+
user.provider = provider;
176+
user.providerId = providerId;
177+
user.password = null; // 소셜 로그인은 비밀번호 없음
178+
user.role = Role.USER;
179+
user.grade = Grade.SPROUT;
180+
user.status = Status.ACTIVE;
181+
user.money = 0;
182+
user.point = 0;
183+
user.isArtistVerified = false;
184+
user.privacyRequiredAgreed = true; // OAuth 로그인 시 필수 동의로 간주
185+
user.marketingAgreed = false;
186+
user.termsAgreedAt = LocalDateTime.now();
187+
return user;
188+
}
189+
190+
// 소셜 로그인 사용자인지 확인
191+
public boolean isOAuthUser() {
192+
return !Provider.LOCAL.equals(this.provider);
193+
}
194+
195+
// OAuth 프로필 정보 업데이트 (재로그인 시)
196+
public void updateOAuthProfile(String name, String profileImageUrl) {
197+
if (name != null && !name.isBlank()) {
198+
this.name = name;
199+
}
200+
if (profileImageUrl != null && !profileImageUrl.isBlank()) {
201+
this.profileImageUrl = profileImageUrl;
202+
}
203+
}
166204

167-
// TODO: 정적 팩토리 메서드 - 소셜 로그인 구현
168205
}

src/main/java/com/back/domain/user/repository/UserRepository.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.back.domain.user.repository;
22

3+
import com.back.domain.user.entity.Provider;
34
import com.back.domain.user.entity.User;
45
import org.springframework.data.jpa.repository.JpaRepository;
56

@@ -21,4 +22,13 @@ public interface UserRepository extends JpaRepository<User, Long>{
2122
boolean existsByNameAndIdNot(String name, Long id);
2223
boolean existsByPhoneAndIdNot(String phone, Long id);
2324
*/
25+
26+
// OAuth 로그인 시 기존 사용자 확인용
27+
Optional<User> findByProviderAndProviderId(Provider provider, String providerId);
28+
29+
// 동일 이메일의 다른 Provider 계정 확인용
30+
Optional<User> findByEmailAndProvider(String email, Provider provider);
31+
32+
// 이메일과 Provider로 사용자 찾기
33+
boolean existsByEmailAndProvider(String email, Provider provider);
2434
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
package com.back.global.security.oauth2;
2+
3+
import java.util.Map;
4+
5+
/**
6+
* Google OAuth2 사용자 정보 구현체
7+
*
8+
* Google OAuth2 응답 예시:
9+
* {
10+
* "sub": "1234567890", // Google 고유 ID
11+
* "name": "홍길동",
12+
* "email": "hong@gmail.com",
13+
* "picture": "https://lh3.googleusercontent.com/..."
14+
* }
15+
*/
16+
public class GoogleUserInfo implements OAuth2UserInfo {
17+
18+
private final Map<String, Object> attributes;
19+
20+
// SpringSecurity가 Google로부터 받은 JSON을 Map 형태로 전달
21+
public GoogleUserInfo(Map<String, Object> attributes) {
22+
this.attributes = attributes;
23+
}
24+
25+
@Override
26+
public String getProviderId() {
27+
return (String) attributes.get("sub");
28+
}
29+
30+
@Override
31+
public String getProvider() {
32+
return "GOOGLE";
33+
}
34+
35+
@Override
36+
public String getEmail() {
37+
return (String) attributes.get("email");
38+
}
39+
40+
@Override
41+
public String getName() {
42+
return (String) attributes.get("name");
43+
}
44+
45+
@Override
46+
public String getProfileImageUrl() {
47+
return (String) attributes.get("picture");
48+
}
49+
50+
}
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
package com.back.global.security.oauth2;
2+
3+
import java.util.Map;
4+
5+
/**
6+
* Kakao Oauth2 사용자 정보 구현체
7+
*
8+
* Kakao OAuth2 응답 예시:
9+
* {
10+
* "id": 1234567890,
11+
* "properties": {
12+
* "nickname": "홍길동",
13+
* "profile_image": "https://k.kakaocdn.net/..."
14+
* },
15+
* "kakao_account": {
16+
* "email": "hong@kakao.com"
17+
* }
18+
* }
19+
*/
20+
public class KakaoUserInfo implements OAuth2UserInfo{
21+
22+
private final Map<String, Object> attributes;
23+
24+
// SpringSecurity가 Kakao로부터 받은 JSON을 Map 형태로 전달
25+
public KakaoUserInfo(Map<String, Object> attributes) {
26+
this.attributes = attributes;
27+
}
28+
29+
@Override
30+
public String getProviderId() {
31+
// Kakao는 id를 숫자로 주므로 String으로 변환
32+
return String.valueOf(attributes.get("id"));
33+
}
34+
35+
@Override
36+
public String getProvider() {
37+
return "KAKAO";
38+
}
39+
40+
@Override
41+
public String getEmail() {
42+
Map<String, Object> kakaoAccount = (Map<String, Object>) attributes.get("kakao_account");
43+
if (kakaoAccount == null) {
44+
return null;
45+
}
46+
return (String) kakaoAccount.get("email");
47+
}
48+
49+
@Override
50+
public String getName() {
51+
Map<String, Object> properties = (Map<String, Object>) attributes.get("properties");
52+
if (properties == null) {
53+
return null;
54+
}
55+
return (String) properties.get("nickname");
56+
}
57+
58+
@Override
59+
public String getProfileImageUrl() {
60+
Map<String, Object> properties = (Map<String, Object>) attributes.get("properties");
61+
if (properties == null) {
62+
return null;
63+
}
64+
return (String) properties.get("profile_image");
65+
}
66+
67+
}
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
package com.back.global.security.oauth2;
2+
3+
import java.util.Map;
4+
5+
/**
6+
* Naver OAuth2 사용자 정보 구현체
7+
*
8+
* Naver OAuth2 응답 예시:
9+
* {
10+
* "resultcode": "00",
11+
* "message": "success",
12+
* "response": {
13+
* "id": "1234567890",
14+
* "name": "홍길동",
15+
* "email": "hong@naver.com",
16+
* "profile_image": "https://phinf.pstatic.net/..."
17+
* }
18+
* }
19+
*/
20+
public class NaverUserInfo implements OAuth2UserInfo {
21+
22+
private final Map<String, Object> attributes;
23+
24+
// SpringSecurity가 Naver로부터 받은 JSON을 Map 형태로 전달
25+
public NaverUserInfo(Map<String, Object> attributes) {
26+
this.attributes = attributes;
27+
}
28+
29+
@Override
30+
public String getProviderId() {
31+
Map<String, Object> response = (Map<String, Object>) attributes.get("response");
32+
if (response == null) {
33+
return null;
34+
}
35+
return (String) response.get("id");
36+
}
37+
38+
@Override
39+
public String getProvider() {
40+
return "NAVER";
41+
}
42+
43+
@Override
44+
public String getEmail() {
45+
Map<String, Object> response = (Map<String, Object>) attributes.get("response");
46+
if (response == null) {
47+
return null;
48+
}
49+
return (String) response.get("email");
50+
}
51+
52+
@Override
53+
public String getName() {
54+
Map<String, Object> response = (Map<String, Object>) attributes.get("response");
55+
if (response == null) {
56+
return null;
57+
}
58+
return (String) response.get("name");
59+
}
60+
61+
@Override
62+
public String getProfileImageUrl() {
63+
Map<String, Object> response = (Map<String, Object>) attributes.get("response");
64+
if (response == null) {
65+
return null;
66+
}
67+
return (String) response.get("profile_image");
68+
}
69+
70+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package com.back.global.security.oauth2;
2+
3+
/**
4+
* Google, Kakao, Naver 등 각 Provider의 응답 형식이 다르기 때문에
5+
* OAuth2 Provider 별로 사용자 정보를 추상화하기 위한 인터페이스
6+
*/
7+
public interface OAuth2UserInfo {
8+
9+
// Provider 고유 ID (예: Google의 sub, Kakao의 id 등)
10+
String getProviderId();
11+
12+
// Provider 이름 (예: google, kakao, naver 등)
13+
String getProvider();
14+
15+
String getEmail();
16+
String getName();
17+
String getProfileImageUrl();
18+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package com.back.global.security.oauth2;
2+
3+
import com.back.global.exception.ServiceException;
4+
5+
import java.util.Map;
6+
7+
/**
8+
* OAuth2UserInfo 팩토리 클래스
9+
* 주어진 Provider에 따라 적절한 OAuth2UserInfo 구현체를 생성
10+
*/
11+
public class OAuth2UserInfoFactory {
12+
13+
public static OAuth2UserInfo getAuth2UserInfo(String registrationId, Map<String, Object> attributes) {
14+
return switch (registrationId.toUpperCase()) {
15+
case "GOOGLE" -> new GoogleUserInfo(attributes);
16+
case "KAKAO" -> new KakaoUserInfo(attributes);
17+
case "NAVER" -> new NaverUserInfo(attributes);
18+
default -> throw new ServiceException("400", "지원하지 않는 소셜 로그인 제공자입니다: " + registrationId);
19+
};
20+
}
21+
}

0 commit comments

Comments
 (0)