Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
Expand Down Expand Up @@ -156,7 +157,7 @@ public String updateMenuSortOrder(List<MenuSortUpdateRequest> requests, MemberDe
}

Map<Long, Long> idToSort = requests.stream()
.collect(java.util.stream.Collectors.toMap(MenuSortUpdateRequest::getMenuId,
.collect(Collectors.toMap(MenuSortUpdateRequest::getMenuId,
MenuSortUpdateRequest::getSortOrder));

menus.forEach(m -> m.updateSortOrder(idToSort.get(m.getId())));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.web.cors.CorsConfigurationSource;

import com.nowait.applicationuser.oauth.oauth2.CustomOAuth2UserService;
import com.nowait.applicationuser.oauth.service.CustomOAuth2UserService;
import com.nowait.applicationuser.oauth.oauth2.OAuth2LoginSuccessHandler;
import com.nowait.applicationuser.security.jwt.JwtAuthorizationFilter;
import com.nowait.applicationuser.security.jwt.JwtUtil;
Expand Down Expand Up @@ -58,6 +58,7 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
"/oauth2/authorization/kakao", // 카카오 로그인 요청
"/login/oauth2/code/**", // 카카오 인증 콜백
"/api/refresh-token", // refresh token (토큰 갱신)
"/v2/app/oauth/kakao/login", // 카카오 앱 로그인
"/v1/menus/**", // 모든 메뉴 조회
"/v1/store-payments/**", // 결제 관련 API
"/orders/**",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package com.nowait.applicationuser.oauth.controller;

import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.nowait.applicationuser.oauth.dto.KakaoAppLoginRequest;
import com.nowait.applicationuser.oauth.dto.KakaoAppLoginResponse;
import com.nowait.applicationuser.oauth.service.KakaoAppLoginService;
import com.nowait.common.api.ApiUtils;

import lombok.RequiredArgsConstructor;

@RestController
@RequestMapping("/v2/app/oauth/kakao")
@RequiredArgsConstructor
public class KakaoAppAuthController {

private final KakaoAppLoginService kakaoAppLoginService;

@PostMapping("/login")
public ResponseEntity<?> kakaoAppLogin(@RequestBody KakaoAppLoginRequest request) {

KakaoAppLoginResponse response = kakaoAppLoginService.login(request);

return ResponseEntity
.status(HttpStatus.OK)
.body(
ApiUtils.success(response)
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.nowait.applicationuser.oauth.dto;

import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@AllArgsConstructor
public class KakaoAppLoginRequest {
private String kakaoAccessToken;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package com.nowait.applicationuser.oauth.dto;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Getter
@NoArgsConstructor(access = lombok.AccessLevel.PROTECTED)
@AllArgsConstructor
@Builder
public class KakaoAppLoginResponse{
private String accessToken;
private String refreshToken;
private Long userId;
private String email;
private String nickName;
private String profileImage;
private boolean phoneEntered;
private boolean marketingAgree;
private boolean isNewUser;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.nowait.applicationuser.oauth.dto;

import com.nowait.domaincorerdb.user.entity.User;

import lombok.AllArgsConstructor;
import lombok.Getter;

@Getter
@AllArgsConstructor
public class OAuthUserResult {
private final User user;
private final boolean newUser;
}
Original file line number Diff line number Diff line change
@@ -1,18 +1,15 @@
package com.nowait.applicationuser.oauth.oauth2;

import java.io.IOException;
import java.time.LocalDateTime;
import java.util.Optional;

import org.springframework.http.ResponseCookie;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import com.nowait.applicationuser.security.jwt.JwtUtil;
import com.nowait.domaincorerdb.token.entity.Token;
import com.nowait.domaincorerdb.token.repository.TokenRepository;
import com.nowait.applicationuser.token.dto.AuthenticationResponse;
import com.nowait.applicationuser.token.service.AuthTokenService;
import com.nowait.domaincorerdb.user.entity.User;
import com.nowait.domainuserrdb.oauth.dto.CustomOAuth2User;

Expand All @@ -30,8 +27,7 @@
@RequiredArgsConstructor
@Slf4j
public class OAuth2LoginSuccessHandler extends SimpleUrlAuthenticationSuccessHandler {
private final JwtUtil jwtUtil;
private final TokenRepository tokenRepository;
private final AuthTokenService authTokenService;

@Override
@Transactional
Expand All @@ -40,26 +36,11 @@ public void onAuthenticationSuccess(HttpServletRequest request, HttpServletRespo

CustomOAuth2User customUserDetails = (CustomOAuth2User)authentication.getPrincipal();
User user = customUserDetails.getUser();
Long userId = customUserDetails.getUserId();
String role = authentication.getAuthorities().iterator().next().getAuthority();

// JWT 발급
String accessToken = jwtUtil.createAccessToken("accessToken", userId, role,
Boolean.TRUE.equals(user.getPhoneEntered()), Boolean.TRUE.equals(user.getIsMarketingAgree()),60 * 60 * 1000L); // 1시간
String refreshToken = jwtUtil.createRefreshToken("refreshToken", userId, 30L * 24 * 60 * 60 * 1000L); // 30일

// 1. refreshToken을 DB에 저장 or update
Optional<Token> tokenOptional = tokenRepository.findByUserId(user.getId());
if (tokenOptional.isPresent()) {
Token token = tokenOptional.get();
token.updateRefreshToken(refreshToken, LocalDateTime.now().plusDays(30));
} else {
Token token = Token.toEntity(user, refreshToken, LocalDateTime.now().plusDays(30));
tokenRepository.save(token);
}
AuthenticationResponse authenticationResponse = authTokenService.issueTokens(user);

// 2. refreshToken을 HttpOnly 쿠키로 설정 (ResponseCookie로)
ResponseCookie refreshTokenCookie = ResponseCookie.from("refreshToken", refreshToken)
ResponseCookie refreshTokenCookie = ResponseCookie.from("refreshToken", authenticationResponse.getRefreshToken())
.httpOnly(true)
.secure(false) // 운영환경에서는 true
.path("/")
Expand All @@ -71,7 +52,7 @@ public void onAuthenticationSuccess(HttpServletRequest request, HttpServletRespo
response.setHeader("Set-Cookie", refreshTokenCookie.toString());

// 3. 프론트엔드로 리다이렉트 (accessToken만 쿼리로 전달)
String targetUrl = "https://app.nowait.co.kr/login/success?accessToken=" + accessToken;
String targetUrl = "https://app.nowait.co.kr/login/success?accessToken=" + authenticationResponse.getAccessToken();
response.sendRedirect(targetUrl);
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,4 @@
package com.nowait.applicationuser.oauth.oauth2;

import java.time.LocalDateTime;
import java.util.Optional;
package com.nowait.applicationuser.oauth.service;

import org.springframework.security.oauth2.client.userinfo.DefaultOAuth2UserService;
import org.springframework.security.oauth2.client.userinfo.OAuth2UserRequest;
Expand All @@ -11,10 +8,8 @@

import com.nowait.applicationuser.oauth.dto.KaKaoResponse;
import com.nowait.applicationuser.oauth.dto.OAuth2Response;
import com.nowait.common.enums.Role;
import com.nowait.common.enums.SocialType;
import com.nowait.applicationuser.oauth.dto.OAuthUserResult;
import com.nowait.domaincorerdb.user.entity.User;
import com.nowait.domaincorerdb.user.repository.UserRepository;
import com.nowait.domainuserrdb.oauth.dto.CustomOAuth2User;

import lombok.RequiredArgsConstructor;
Expand All @@ -25,12 +20,13 @@
@RequiredArgsConstructor
@Slf4j
public class CustomOAuth2UserService extends DefaultOAuth2UserService {
private final UserRepository userRepository;
private final OAuthUserService oAuthUserService;
Copy link

@coderabbitai coderabbitai bot Dec 15, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

OAuth 사용자/속성 전체를 INFO 레벨로 로그에 남기는 것은 PII 노출 위험이 있습니다

log.info("CustomOAuth2UserService :: {}", oAuth2User);log.info("oAuthUser.getAttributes :: {}", oAuth2User.getAttributes()); 는 이메일, 프로필 이미지 등 개인정보가 포함된 전체 OAuth 응답을 그대로 애플리케이션 로그에 남깁니다. 운영 환경에서 INFO 로그는 수집/보관 범위가 넓어서, 개인정보 보호/컴플라이언스 관점에서 리스크가 큽니다.

  • 운영 기준으로는 최소한 DEBUG 이하로 내리거나,
  • provider, providerId 정도의 최소 정보만 로그로 남기고 raw attributes 는 남기지 않는 방향을 추천드립니다.

예시:

- log.info("CustomOAuth2UserService :: {}", oAuth2User);
- log.info("oAuthUser.getAttributes :: {}", oAuth2User.getAttributes());
+ log.debug("CustomOAuth2UserService loaded user. provider={}, attributeKeys={}",
+    registrationId,
+    oAuth2User.getAttributes().keySet());

이렇게 하면 디버깅에 필요한 정보는 유지하면서, 실제 PII/토큰 값 노출은 피할 수 있습니다.

Also applies to: 28-29, 40-44

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

해당 로그 삭제 여부 검토 필요하니 이슈 등록해줘

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
gh issue create \
  --repo GTable/NoWait_BE_MultiModule \
  --title "CustomOAuth2UserService의 개인정보 로그 노출 검토 필요" \
  --body "## 개요
CustomOAuth2UserService에서 OAuth 사용자 정보를 INFO 레벨로 로그에 기록하고 있어 개인정보(이메일, 프로필 이미지 등) 노출 위험이 있습니다.

## 위치
\`nowait-app-user-api/src/main/java/com/nowait/applicationuser/oauth/service/CustomOAuth2UserService.java\`

## 검토 사항
- \`log.info(\"CustomOAuth2UserService :: {}\", oAuth2User);\` 삭제 또는 DEBUG 레벨로 변경
- \`log.info(\"oAuthUser.getAttributes :: {}\", oAuth2User.getAttributes());\` 삭제 또는 DEBUG 레벨로 변경
- 필요시 최소한의 정보(provider, providerId 등)만 로그에 남기는 방안 검토

## 관련 링크
- PR: https://github.com/GTable/NoWait_BE_MultiModule/pull/335
- 코멘트: https://github.com/GTable/NoWait_BE_MultiModule/pull/335#discussion_r2619398338

요청자: @Jjiggu" \
  --assignee Jjiggu

Length of output: 58


@Jjiggu, 이슈를 생성했습니다!

이슈 #336: CustomOAuth2UserService의 개인정보 로그 노출 검토 필요

해당 이슈에 로그 삭제 또는 DEBUG 레벨 변경 검토 사항을 정리해두었으며, 이 PR과 코멘트 링크도 포함했습니다. 담당자로 배정되었으니 검토 후 처리 부탁드립니다.


🧬 Code Graph Analysis Results

filename:nowait-app-user-api/src/main/java/com/nowait/applicationuser/oauth/dto/KaKaoResponse.java
At lines 8-40:

@RequiredArgsConstructor
public class KaKaoResponse implements OAuth2Response {
	private final Map<String, Object> attributes;

	@Override
	public String getProvider() {
		return "kakao";
	}

	@Override
	public String getProviderId() {
		return attributes.get("id").toString();
	}

	@Override
	public String getEmail() {
		Map<String, Object> kakaoAccount = (Map<String, Object>)attributes.get("kakao_account");
		return kakaoAccount.get("email").toString();
	}

	@Override
	public String getNickName() {
		Map<String, Object> properties = (Map<String, Object>)attributes.get("properties");
		return properties.get("nickname").toString();
	}

	@Override
	public String getProfileImage() {
		Map<String, Object> properties = (Map<String, Object>)attributes.get("properties");
		return properties.get("profile_image").toString();
	}

}

filename:nowait-domain/domain-user-rdb/src/main/java/com/nowait/domainuserrdb/oauth/dto/CustomOAuth2User.java
At lines 15-64:

@RequiredArgsConstructor
@Getter
public class CustomOAuth2User implements OAuth2User {
	private final User user;
	private final boolean newUser;

	@Override
	public Map<String, Object> getAttributes() {
		return null;
	}

	// 사용자가 가지는 권한 설정
	@Override
	public Collection<? extends GrantedAuthority> getAuthorities() {
		Collection<GrantedAuthority> authorities = new ArrayList<>();

		authorities.add(new GrantedAuthority() {
			@Override
			public String getAuthority() {
				return user.getRole().getName(); // 유저의 권한 리턴
			}
		});

		return authorities;
	}

	// JWT 인증 시 (항상 기존 유저 취급)
	public CustomOAuth2User(User user) {
		this.user = user;
		this.newUser = false;
	}

	@Override
	public String getName() {
		return user.getEmail();
	}

	public User getUser() {
		return user;
	}

	public Long getUserId() {
		return user.getId();
	}

	public String getNickname() {
		return user.getNickname();
	}

}

filename:nowait-app-user-api/src/main/java/com/nowait/applicationuser/oauth/service/OAuthUserService.java
At lines 17-49:

@Service
@RequiredArgsConstructor
public class OAuthUserService {
	private final UserRepository userRepository;

	@Transactional
	public OAuthUserResult loadOrCreateUser(OAuth2Response oAuth2Response) {
		return userRepository.findByEmail(oAuth2Response.getEmail())
			.map(user -> new OAuthUserResult(user, false))   // 기존 유저
			.orElseGet(() -> {
				User created = createUser(oAuth2Response);
				return new OAuthUserResult(created, true);  // 신규 유저
			});
	}

	private User createUser(OAuth2Response oAuth2Response) {
		User user = User.builder()
			.email(oAuth2Response.getEmail())
			.phoneNumber("")
			.nickname(oAuth2Response.getNickName())
			.profileImage(oAuth2Response.getProfileImage())
			.socialType(SocialType.KAKAO)
			.role(Role.USER) // 일반 유저 설정
			.storeId(0L)
			.phoneEntered(false)
			.isMarketingAgree(false)
			.createdAt(LocalDateTime.now())
			.updatedAt(LocalDateTime.now())
			.build();

		return userRepository.save(user);
	}
}

filename:nowait-app-user-api/src/main/java/com/nowait/applicationuser/oauth/service/KakaoAppLoginService.java
At lines 22-69:

@Service
@RequiredArgsConstructor
public class KakaoAppLoginService {

	private final CustomOAuth2UserService customOAuth2UserService;
	private final ClientRegistrationRepository clientRegistrationRepository;
	private final AuthTokenService authTokenService;

	public KakaoAppLoginResponse login(KakaoAppLoginRequest request) {
		String kakaoAccessTokenValue = request.getKakaoAccessToken();

		ClientRegistration kakaoRegistration = clientRegistrationRepository.findByRegistrationId("kakao");

		if (kakaoRegistration == null) {
			throw new OAuth2AuthenticationException("Kakao Client Registration not found.");
		}

		OAuth2AccessToken kakaoAccessToken = new OAuth2AccessToken(
			OAuth2AccessToken.TokenType.BEARER,
			kakaoAccessTokenValue,
			Instant.now(),
			null
		);

		OAuth2UserRequest userRequest = new OAuth2UserRequest(
			kakaoRegistration,
			kakaoAccessToken
		);

		OAuth2User oAuth2User = customOAuth2UserService.loadUser(userRequest);
		CustomOAuth2User customUser = (CustomOAuth2User) oAuth2User;
		User user = customUser.getUser();

		AuthenticationResponse authenticationResponse = authTokenService.issueTokens(user);

		return KakaoAppLoginResponse.builder()
			.accessToken(authenticationResponse.getAccessToken())
			.refreshToken(authenticationResponse.getRefreshToken())
			.userId(user.getId())
			.email(user.getEmail())
			.nickName(user.getNickname())
			.profileImage(user.getProfileImage())
			.phoneEntered(user.getPhoneEntered())
			.marketingAgree(user.getIsMarketingAgree())
			.isNewUser(customUser.isNewUser())
			.build();
	}
}


@Override
public OAuth2User loadUser(OAuth2UserRequest userRequest) throws OAuth2AuthenticationException {
OAuth2User oAuth2User = super.loadUser(userRequest);

// TODO : 해당 로그 필요한지 추후 확인 필요
log.info("CustomOAuth2UserService :: {}", oAuth2User);
log.info("oAuthUser.getAttributes :: {}", oAuth2User.getAttributes());

Expand All @@ -44,34 +40,10 @@ public OAuth2User loadUser(OAuth2UserRequest userRequest) throws OAuth2Authentic
}

// DB에 유저가 있는지 판단
Optional<User> foundUser = userRepository.findByEmail(oAuth2Response.getEmail());

// DB에 유저 없으면 - 회원가입
if (foundUser.isEmpty()) {

User user = User.builder()
.email(oAuth2Response.getEmail())
.phoneNumber("")
.nickname(oAuth2Response.getNickName())
.profileImage(oAuth2Response.getProfileImage())
.socialType(SocialType.KAKAO)
.role(Role.USER) // 일반 유저 설정
.storeId(0L)
.phoneEntered(false)
.isMarketingAgree(false)
.createdAt(LocalDateTime.now())
.updatedAt(LocalDateTime.now())
.build();

userRepository.save(user);
OAuthUserResult result = oAuthUserService.loadOrCreateUser(oAuth2Response);
User user = result.getUser();
boolean newUser = result.isNewUser();

return new CustomOAuth2User(user);
} else {
// DB에 유저 존재하면 - 로그인 진행 (이때 로그인 처리는 안하고, OAuth2LoginSuccessHandler에서 담당함)
User user = foundUser.get();

return new CustomOAuth2User(user);
}
return new CustomOAuth2User(user, newUser);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package com.nowait.applicationuser.oauth.service;

import java.time.Instant;

import org.springframework.security.oauth2.client.registration.ClientRegistration;
import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository;
import org.springframework.security.oauth2.client.userinfo.OAuth2UserRequest;
import org.springframework.security.oauth2.core.OAuth2AccessToken;
import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
import org.springframework.security.oauth2.core.user.OAuth2User;
import org.springframework.stereotype.Service;

import com.nowait.applicationuser.oauth.dto.KakaoAppLoginRequest;
import com.nowait.applicationuser.oauth.dto.KakaoAppLoginResponse;
import com.nowait.applicationuser.token.dto.AuthenticationResponse;
import com.nowait.applicationuser.token.service.AuthTokenService;
import com.nowait.domaincorerdb.user.entity.User;
import com.nowait.domainuserrdb.oauth.dto.CustomOAuth2User;

import lombok.RequiredArgsConstructor;

@Service
@RequiredArgsConstructor
public class KakaoAppLoginService {

private final CustomOAuth2UserService customOAuth2UserService;
private final ClientRegistrationRepository clientRegistrationRepository;
private final AuthTokenService authTokenService;

public KakaoAppLoginResponse login(KakaoAppLoginRequest request) {
String kakaoAccessTokenValue = request.getKakaoAccessToken();

if (kakaoAccessTokenValue == null || kakaoAccessTokenValue.isEmpty()) {
throw new OAuth2AuthenticationException("Kakao Access Token is missing.");
}

ClientRegistration kakaoRegistration = clientRegistrationRepository.findByRegistrationId("kakao");

if (kakaoRegistration == null) {
throw new OAuth2AuthenticationException("Kakao Client Registration not found.");
}

OAuth2AccessToken kakaoAccessToken = new OAuth2AccessToken(
OAuth2AccessToken.TokenType.BEARER,
kakaoAccessTokenValue,
Instant.now(),
null
);

OAuth2UserRequest userRequest = new OAuth2UserRequest(
kakaoRegistration,
kakaoAccessToken
);

OAuth2User oAuth2User = customOAuth2UserService.loadUser(userRequest);
CustomOAuth2User customUser = (CustomOAuth2User) oAuth2User;
User user = customUser.getUser();
Comment on lines +55 to +57
Copy link

@coderabbitai coderabbitai bot Dec 15, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

ClassCastException 발생 가능성

loadUser가 반환하는 OAuth2UserCustomOAuth2User로 직접 캐스팅하고 있습니다. 예상치 못한 구현체가 반환될 경우 런타임 예외가 발생합니다.

 OAuth2User oAuth2User = customOAuth2UserService.loadUser(userRequest);
-CustomOAuth2User customUser = (CustomOAuth2User) oAuth2User;
+if (!(oAuth2User instanceof CustomOAuth2User customUser)) {
+	throw new OAuth2AuthenticationException("Unexpected OAuth2User type");
+}
 User user = customUser.getUser();
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
OAuth2User oAuth2User = customOAuth2UserService.loadUser(userRequest);
CustomOAuth2User customUser = (CustomOAuth2User) oAuth2User;
User user = customUser.getUser();
OAuth2User oAuth2User = customOAuth2UserService.loadUser(userRequest);
if (!(oAuth2User instanceof CustomOAuth2User customUser)) {
throw new OAuth2AuthenticationException("Unexpected OAuth2User type");
}
User user = customUser.getUser();
🤖 Prompt for AI Agents
In
nowait-app-user-api/src/main/java/com/nowait/applicationuser/oauth/service/KakaoAppLoginService.java
around lines 51 to 53, the code directly casts OAuth2User to CustomOAuth2User
which can throw ClassCastException; update the method to safely handle other
implementations by checking if oAuth2User is an instance of CustomOAuth2User
before casting, and if not either adapt the OAuth2User to your User domain
(extract required attributes and build a User) or throw a clear, specific
exception with contextual details; also add a null check for oAuth2User and
ensure any created/adapted User is validated before further processing.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

추후 개선

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Jjiggu, 알겠습니다! 나중에 개선하시는 것으로 하겠습니다.

필요하시면 추후 개선 작업을 추적하기 위한 이슈를 생성해 드릴 수 있습니다. 원하시면 말씀해 주세요! 😊


AuthenticationResponse authenticationResponse = authTokenService.issueTokens(user);

return KakaoAppLoginResponse.builder()
.accessToken(authenticationResponse.getAccessToken())
.refreshToken(authenticationResponse.getRefreshToken())
.userId(user.getId())
.email(user.getEmail())
.nickName(user.getNickname())
.profileImage(user.getProfileImage())
.phoneEntered(user.getPhoneEntered())
.marketingAgree(user.getIsMarketingAgree())
.isNewUser(customUser.isNewUser())
.build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package com.nowait.applicationuser.oauth.service;

import java.time.LocalDateTime;

import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.nowait.applicationuser.oauth.dto.OAuth2Response;
import com.nowait.applicationuser.oauth.dto.OAuthUserResult;
import com.nowait.common.enums.Role;
import com.nowait.common.enums.SocialType;
import com.nowait.domaincorerdb.user.entity.User;
import com.nowait.domaincorerdb.user.repository.UserRepository;

import lombok.RequiredArgsConstructor;

@Service
@RequiredArgsConstructor
public class OAuthUserService {
private final UserRepository userRepository;

@Transactional
public OAuthUserResult loadOrCreateUser(OAuth2Response oAuth2Response) {
return userRepository.findByEmail(oAuth2Response.getEmail())
.map(user -> new OAuthUserResult(user, false)) // 기존 유저
.orElseGet(() -> {
User created = createUser(oAuth2Response);
return new OAuthUserResult(created, true); // 신규 유저
});
}

private User createUser(OAuth2Response oAuth2Response) {
User user = User.builder()
.email(oAuth2Response.getEmail())
.phoneNumber("")
.nickname(oAuth2Response.getNickName())
.profileImage(oAuth2Response.getProfileImage())
.socialType(SocialType.KAKAO)
.role(Role.USER) // 일반 유저 설정
.storeId(0L)
.phoneEntered(false)
.isMarketingAgree(false)
.createdAt(LocalDateTime.now())
.updatedAt(LocalDateTime.now())
.build();

return userRepository.save(user);
}
}
Loading