카카오 로그인 추가
This commit is contained in:
@@ -0,0 +1,54 @@
|
||||
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
|
||||
)
|
||||
}
|
||||
}
|
@@ -0,0 +1,15 @@
|
||||
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 }
|
||||
}
|
@@ -0,0 +1,53 @@
|
||||
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
|
||||
}
|
||||
}
|
@@ -0,0 +1,7 @@
|
||||
package kr.co.vividnext.sodalive.member.social.kakao
|
||||
|
||||
data class KakaoUserInfo(
|
||||
val id: Long,
|
||||
val email: String,
|
||||
val nickname: String?
|
||||
)
|
Reference in New Issue
Block a user