Compare commits
No commits in common. "d822a4a8accdf85cd9c74ca34d835c7e9460c1c7" and "a301f854ba523a7c9babb108aecf6f75657402c2" have entirely different histories.
d822a4a8ac
...
a301f854ba
|
@ -38,7 +38,6 @@ class AdminRecommendSeriesQueryRepositoryImpl(
|
||||||
.and(series.isActive.isTrue)
|
.and(series.isActive.isTrue)
|
||||||
.and(recommendSeries.isFree.eq(isFree))
|
.and(recommendSeries.isFree.eq(isFree))
|
||||||
)
|
)
|
||||||
.orderBy(recommendSeries.orders.asc())
|
|
||||||
.fetch()
|
.fetch()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -71,7 +71,6 @@ class SecurityConfig(
|
||||||
.antMatchers("/member/signup/v2").permitAll()
|
.antMatchers("/member/signup/v2").permitAll()
|
||||||
.antMatchers("/member/login").permitAll()
|
.antMatchers("/member/login").permitAll()
|
||||||
.antMatchers("/member/login/google").permitAll()
|
.antMatchers("/member/login/google").permitAll()
|
||||||
.antMatchers("/member/login/kakao").permitAll()
|
|
||||||
.antMatchers("/creator-admin/member/login").permitAll()
|
.antMatchers("/creator-admin/member/login").permitAll()
|
||||||
.antMatchers("/member/forgot-password").permitAll()
|
.antMatchers("/member/forgot-password").permitAll()
|
||||||
.antMatchers("/stplat/terms_of_service").permitAll()
|
.antMatchers("/stplat/terms_of_service").permitAll()
|
||||||
|
|
|
@ -12,7 +12,6 @@ import kr.co.vividnext.sodalive.member.login.SocialLoginRequest
|
||||||
import kr.co.vividnext.sodalive.member.notification.UpdateNotificationSettingRequest
|
import kr.co.vividnext.sodalive.member.notification.UpdateNotificationSettingRequest
|
||||||
import kr.co.vividnext.sodalive.member.signUp.SignUpRequestV2
|
import kr.co.vividnext.sodalive.member.signUp.SignUpRequestV2
|
||||||
import kr.co.vividnext.sodalive.member.social.google.GoogleAuthService
|
import kr.co.vividnext.sodalive.member.social.google.GoogleAuthService
|
||||||
import kr.co.vividnext.sodalive.member.social.kakao.KakaoAuthService
|
|
||||||
import org.springframework.data.domain.Pageable
|
import org.springframework.data.domain.Pageable
|
||||||
import org.springframework.security.core.annotation.AuthenticationPrincipal
|
import org.springframework.security.core.annotation.AuthenticationPrincipal
|
||||||
import org.springframework.security.core.userdetails.User
|
import org.springframework.security.core.userdetails.User
|
||||||
|
@ -32,7 +31,6 @@ import org.springframework.web.multipart.MultipartFile
|
||||||
@RequestMapping("/member")
|
@RequestMapping("/member")
|
||||||
class MemberController(
|
class MemberController(
|
||||||
private val service: MemberService,
|
private val service: MemberService,
|
||||||
private val kakaoAuthService: KakaoAuthService,
|
|
||||||
private val googleAuthService: GoogleAuthService,
|
private val googleAuthService: GoogleAuthService,
|
||||||
private val trackingService: AdTrackingService
|
private val trackingService: AdTrackingService
|
||||||
) {
|
) {
|
||||||
|
@ -344,27 +342,4 @@ class MemberController(
|
||||||
|
|
||||||
return ApiResponse.ok(message = "회원가입을 축하드립니다.", data = response.loginResponse)
|
return ApiResponse.ok(message = "회원가입을 축하드립니다.", data = response.loginResponse)
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping("/login/kakao")
|
|
||||||
fun loginKakao(
|
|
||||||
@RequestHeader("Authorization") authHeader: String,
|
|
||||||
@RequestBody request: SocialLoginRequest
|
|
||||||
): ApiResponse<LoginResponse> {
|
|
||||||
if (!authHeader.startsWith("Bearer ")) {
|
|
||||||
throw SodaException("카카오 로그인을 하지 못했습니다. 다시 시도해 주세요")
|
|
||||||
}
|
|
||||||
|
|
||||||
val token = authHeader.substring(7)
|
|
||||||
val response = kakaoAuthService.authenticate(token, request.container, request.marketingPid)
|
|
||||||
|
|
||||||
if (!response.marketingPid.isNullOrBlank()) {
|
|
||||||
trackingService.saveTrackingHistory(
|
|
||||||
pid = response.marketingPid,
|
|
||||||
type = AdTrackingHistoryType.SIGNUP,
|
|
||||||
memberId = response.memberId
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
return ApiResponse.ok(message = "회원가입을 축하드립니다.", data = response.loginResponse)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,7 +22,6 @@ interface MemberRepository : JpaRepository<Member, Long>, MemberQueryRepository
|
||||||
fun findByEmail(email: String): Member?
|
fun findByEmail(email: String): Member?
|
||||||
fun findByNickname(nickname: String): Member?
|
fun findByNickname(nickname: String): Member?
|
||||||
fun findByGoogleId(googleId: String): Member?
|
fun findByGoogleId(googleId: String): Member?
|
||||||
fun findByKakaoId(kakaoId: Long): Member?
|
|
||||||
}
|
}
|
||||||
|
|
||||||
interface MemberQueryRepository {
|
interface MemberQueryRepository {
|
||||||
|
|
|
@ -33,7 +33,6 @@ import kr.co.vividnext.sodalive.member.signUp.SignUpRequestV2
|
||||||
import kr.co.vividnext.sodalive.member.signUp.SignUpResponse
|
import kr.co.vividnext.sodalive.member.signUp.SignUpResponse
|
||||||
import kr.co.vividnext.sodalive.member.signUp.SignUpValidator
|
import kr.co.vividnext.sodalive.member.signUp.SignUpValidator
|
||||||
import kr.co.vividnext.sodalive.member.social.google.GoogleUserInfo
|
import kr.co.vividnext.sodalive.member.social.google.GoogleUserInfo
|
||||||
import kr.co.vividnext.sodalive.member.social.kakao.KakaoUserInfo
|
|
||||||
import kr.co.vividnext.sodalive.member.stipulation.Stipulation
|
import kr.co.vividnext.sodalive.member.stipulation.Stipulation
|
||||||
import kr.co.vividnext.sodalive.member.stipulation.StipulationAgree
|
import kr.co.vividnext.sodalive.member.stipulation.StipulationAgree
|
||||||
import kr.co.vividnext.sodalive.member.stipulation.StipulationAgreeRepository
|
import kr.co.vividnext.sodalive.member.stipulation.StipulationAgreeRepository
|
||||||
|
@ -771,37 +770,4 @@ class MemberService(
|
||||||
|
|
||||||
return member
|
return member
|
||||||
}
|
}
|
||||||
|
|
||||||
@Transactional
|
|
||||||
fun findOrRegister(kakaoUserInfo: KakaoUserInfo, container: String, marketingPid: String?): Member {
|
|
||||||
repository.findByKakaoId(kakaoUserInfo.id)?.let { return it }
|
|
||||||
|
|
||||||
val stipulationTermsOfService = stipulationRepository.findByIdOrNull(StipulationIds.TERMS_OF_SERVICE_ID)
|
|
||||||
?: throw SodaException("잘못된 요청입니다\n앱 종료 후 다시 시도해 주세요.")
|
|
||||||
|
|
||||||
val stipulationPrivacyPolicy = stipulationRepository.findByIdOrNull(StipulationIds.PRIVACY_POLICY_ID)
|
|
||||||
?: throw SodaException("잘못된 요청입니다\n앱 종료 후 다시 시도해 주세요.")
|
|
||||||
|
|
||||||
val nickname = nicknameGenerateService.generateUniqueNickname()
|
|
||||||
val member = Member(
|
|
||||||
kakaoId = kakaoUserInfo.id,
|
|
||||||
email = kakaoUserInfo.email,
|
|
||||||
password = "",
|
|
||||||
nickname = nickname,
|
|
||||||
profileImage = "profile/default-profile.png",
|
|
||||||
gender = Gender.NONE,
|
|
||||||
provider = MemberProvider.KAKAO,
|
|
||||||
container = container
|
|
||||||
)
|
|
||||||
|
|
||||||
if (!marketingPid.isNullOrBlank()) {
|
|
||||||
member.activePid = marketingPid
|
|
||||||
member.partnerExpirationDatetime = LocalDateTime.now().plusYears(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
repository.save(member)
|
|
||||||
agreeTermsOfServiceAndPrivacyPolicy(member, stipulationTermsOfService, stipulationPrivacyPolicy)
|
|
||||||
|
|
||||||
return member
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,54 +0,0 @@
|
||||||
package kr.co.vividnext.sodalive.member.social.kakao
|
|
||||||
|
|
||||||
import kr.co.vividnext.sodalive.common.SodaException
|
|
||||||
import kr.co.vividnext.sodalive.jwt.TokenProvider
|
|
||||||
import kr.co.vividnext.sodalive.member.MemberAdapter
|
|
||||||
import kr.co.vividnext.sodalive.member.MemberService
|
|
||||||
import kr.co.vividnext.sodalive.member.login.LoginResponse
|
|
||||||
import kr.co.vividnext.sodalive.member.social.SocialLoginResponse
|
|
||||||
import org.springframework.beans.factory.annotation.Value
|
|
||||||
import org.springframework.security.core.context.SecurityContextHolder
|
|
||||||
import org.springframework.stereotype.Service
|
|
||||||
|
|
||||||
@Service
|
|
||||||
class KakaoAuthService(
|
|
||||||
private val kakaoService: KakaoService,
|
|
||||||
private val memberService: MemberService,
|
|
||||||
private val tokenProvider: TokenProvider,
|
|
||||||
|
|
||||||
@Value("\${cloud.aws.cloud-front.host}")
|
|
||||||
private val cloudFrontHost: String
|
|
||||||
) {
|
|
||||||
fun authenticate(accessToken: String, container: String, marketingPid: String?): SocialLoginResponse {
|
|
||||||
val kakaoUserInfo = kakaoService.getUserInfo(accessToken)
|
|
||||||
?: throw SodaException("카카오 로그인을 하지 못했습니다. 다시 시도해 주세요")
|
|
||||||
val member = memberService.findOrRegister(kakaoUserInfo, container, marketingPid)
|
|
||||||
val principal = MemberAdapter(member)
|
|
||||||
val authToken = KakaoAuthenticationToken(accessToken, principal.authorities)
|
|
||||||
authToken.setPrincipal(principal)
|
|
||||||
SecurityContextHolder.getContext().authentication = authToken
|
|
||||||
|
|
||||||
val jwt = tokenProvider.createToken(
|
|
||||||
authentication = authToken,
|
|
||||||
memberId = member.id!!
|
|
||||||
)
|
|
||||||
|
|
||||||
val loginResponse = LoginResponse(
|
|
||||||
userId = member.id!!,
|
|
||||||
token = jwt,
|
|
||||||
nickname = member.nickname,
|
|
||||||
email = member.email,
|
|
||||||
profileImage = if (member.profileImage != null) {
|
|
||||||
"$cloudFrontHost/${member.profileImage}"
|
|
||||||
} else {
|
|
||||||
"$cloudFrontHost/profile/default-profile.png"
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
return SocialLoginResponse(
|
|
||||||
memberId = member.id!!,
|
|
||||||
marketingPid = marketingPid,
|
|
||||||
loginResponse = loginResponse
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,15 +0,0 @@
|
||||||
package kr.co.vividnext.sodalive.member.social.kakao
|
|
||||||
|
|
||||||
import org.springframework.security.authentication.AbstractAuthenticationToken
|
|
||||||
import org.springframework.security.core.GrantedAuthority
|
|
||||||
|
|
||||||
class KakaoAuthenticationToken(
|
|
||||||
val accessToken: String,
|
|
||||||
authorities: Collection<GrantedAuthority>? = null
|
|
||||||
) : AbstractAuthenticationToken(authorities) {
|
|
||||||
private var principal: Any? = null
|
|
||||||
init { isAuthenticated = authorities != null }
|
|
||||||
override fun getCredentials(): Any = accessToken
|
|
||||||
override fun getPrincipal(): Any? = principal
|
|
||||||
fun setPrincipal(principal: Any) { this.principal = principal }
|
|
||||||
}
|
|
|
@ -1,53 +0,0 @@
|
||||||
package kr.co.vividnext.sodalive.member.social.kakao
|
|
||||||
|
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper
|
|
||||||
import kr.co.vividnext.sodalive.common.SodaException
|
|
||||||
import org.springframework.http.HttpEntity
|
|
||||||
import org.springframework.http.HttpHeaders
|
|
||||||
import org.springframework.http.HttpMethod
|
|
||||||
import org.springframework.http.HttpStatus
|
|
||||||
import org.springframework.http.ResponseEntity
|
|
||||||
import org.springframework.stereotype.Service
|
|
||||||
import org.springframework.web.client.RestTemplate
|
|
||||||
|
|
||||||
@Service
|
|
||||||
class KakaoService(
|
|
||||||
private val restTemplate: RestTemplate = RestTemplate(),
|
|
||||||
private val objectMapper: ObjectMapper = ObjectMapper()
|
|
||||||
) {
|
|
||||||
fun getUserInfo(accessToken: String): KakaoUserInfo? {
|
|
||||||
val url = "https://kapi.kakao.com/v2/user/me"
|
|
||||||
val headers = HttpHeaders().apply {
|
|
||||||
set("Authorization", "Bearer $accessToken")
|
|
||||||
}
|
|
||||||
val entity = HttpEntity<Any>(headers)
|
|
||||||
|
|
||||||
try {
|
|
||||||
val response: ResponseEntity<String> = restTemplate.exchange(
|
|
||||||
url,
|
|
||||||
HttpMethod.GET,
|
|
||||||
entity,
|
|
||||||
String::class.java
|
|
||||||
)
|
|
||||||
|
|
||||||
if (response.statusCode == HttpStatus.OK) {
|
|
||||||
// 응답 JSON을 KakaoUserInfo와 직접 매핑하려면 DTO의 구조와 JSON 구조가 일치해야 합니다.
|
|
||||||
// 실제 응답 JSON은 중첩 구조를 가지므로, 필요한 필드만 추출하는 방법을 사용합니다.
|
|
||||||
val jsonNode = objectMapper.readTree(response.body ?: return null)
|
|
||||||
val id = jsonNode.get("id").asLong()
|
|
||||||
val kakaoAccount = jsonNode.get("kakao_account")
|
|
||||||
val email = kakaoAccount?.get("email")?.asText()
|
|
||||||
?: throw SodaException("카카오 로그인을 하지 못했습니다. 다시 시도해 주세요")
|
|
||||||
val properties = jsonNode.get("properties")
|
|
||||||
val nickname = properties?.get("nickname")?.asText()
|
|
||||||
|
|
||||||
return KakaoUserInfo(id, email, nickname)
|
|
||||||
} else {
|
|
||||||
println("카카오 사용자 정보 요청 실패: ${response.statusCode}")
|
|
||||||
}
|
|
||||||
} catch (ex: Exception) {
|
|
||||||
ex.printStackTrace()
|
|
||||||
}
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,7 +0,0 @@
|
||||||
package kr.co.vividnext.sodalive.member.social.kakao
|
|
||||||
|
|
||||||
data class KakaoUserInfo(
|
|
||||||
val id: Long,
|
|
||||||
val email: String,
|
|
||||||
val nickname: String?
|
|
||||||
)
|
|
Loading…
Reference in New Issue