Skip to content

Commit

Permalink
소셜로그인 로직 통합
Browse files Browse the repository at this point in the history
  • Loading branch information
asp345 committed Sep 20, 2024
1 parent 7e901bd commit 6c05e77
Show file tree
Hide file tree
Showing 2 changed files with 76 additions and 112 deletions.
13 changes: 7 additions & 6 deletions api/src/main/kotlin/handler/UserHandler.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.wafflestudio.snu4t.handler

import com.wafflestudio.snu4t.auth.SocialProvider
import com.wafflestudio.snu4t.common.dto.OkResponse
import com.wafflestudio.snu4t.common.extension.toZonedDateTime
import com.wafflestudio.snu4t.middleware.SnuttRestApiDefaultMiddleware
Expand Down Expand Up @@ -104,39 +105,39 @@ class UserHandler(
handle(req) {
val user = req.getContext().user!!
val socialLoginRequest: SocialLoginRequest = req.awaitBody()
userService.attachFacebook(user, socialLoginRequest)
userService.attachSocial(user, socialLoginRequest, SocialProvider.FACEBOOK)
}

suspend fun attachGoogle(req: ServerRequest): ServerResponse =
handle(req) {
val user = req.getContext().user!!
val socialLoginRequest: SocialLoginRequest = req.awaitBody()
userService.attachGoogle(user, socialLoginRequest)
userService.attachSocial(user, socialLoginRequest, SocialProvider.GOOGLE)
}

suspend fun attachKakao(req: ServerRequest): ServerResponse =
handle(req) {
val user = req.getContext().user!!
val socialLoginRequest: SocialLoginRequest = req.awaitBody()
userService.attachKakao(user, socialLoginRequest)
userService.attachSocial(user, socialLoginRequest, SocialProvider.KAKAO)
}

suspend fun detachFacebook(req: ServerRequest): ServerResponse =
handle(req) {
val user = req.getContext().user!!
userService.detachFacebook(user)
userService.detachSocial(user, SocialProvider.FACEBOOK)
}

suspend fun detachGoogle(req: ServerRequest): ServerResponse =
handle(req) {
val user = req.getContext().user!!
userService.detachGoogle(user)
userService.detachSocial(user, SocialProvider.GOOGLE)
}

suspend fun detachKakao(req: ServerRequest): ServerResponse =
handle(req) {
val user = req.getContext().user!!
userService.detachKakao(user)
userService.detachSocial(user, SocialProvider.KAKAO)
}

suspend fun changePassword(req: ServerRequest): ServerResponse =
Expand Down
175 changes: 69 additions & 106 deletions core/src/main/kotlin/users/service/UserService.kt
Original file line number Diff line number Diff line change
Expand Up @@ -92,27 +92,17 @@ interface UserService {
localLoginRequest: LocalLoginRequest,
): TokenResponse

suspend fun attachFacebook(
suspend fun attachSocial(
user: User,
socialLoginRequest: SocialLoginRequest,
socialProvider: SocialProvider,
): TokenResponse

suspend fun attachGoogle(
suspend fun detachSocial(
user: User,
socialLoginRequest: SocialLoginRequest,
): TokenResponse

suspend fun attachKakao(
user: User,
socialLoginRequest: SocialLoginRequest,
socialProvider: SocialProvider,
): TokenResponse

suspend fun detachFacebook(user: User): TokenResponse

suspend fun detachGoogle(user: User): TokenResponse

suspend fun detachKakao(user: User): TokenResponse

suspend fun changePassword(
user: User,
passwordChangeRequest: PasswordChangeRequest,
Expand Down Expand Up @@ -399,113 +389,86 @@ class UserServiceImpl(
return TokenResponse(token = user.credentialHash)
}

override suspend fun attachFacebook(
override suspend fun attachSocial(
user: User,
socialLoginRequest: SocialLoginRequest,
socialProvider: SocialProvider,
): TokenResponse {
if (user.credential.fbId != null) throw AlreadySocialAccountException
val token = socialLoginRequest.token
val oauth2UserResponse = authService.socialLoginWithAccessToken(SocialProvider.FACEBOOK, token)

if (userRepository.existsByCredentialFbIdAndActiveTrue(oauth2UserResponse.socialId)) {
throw DuplicateSocialAccountException
}
val socialCredential = authService.buildFacebookCredential(oauth2UserResponse)
val oauth2UserResponse = authService.socialLoginWithAccessToken(socialProvider, token)

checkNotNull(oauth2UserResponse.email) { "facebook email is null: $oauth2UserResponse" }
userRepository.findByEmailAndIsEmailVerifiedTrueAndActiveTrue(oauth2UserResponse.email)?.let {
throw DuplicateEmailException(SocialProvider.FACEBOOK)
}
user.apply {
credential.fbId = socialCredential.fbId
credential.fbName = socialCredential.fbName
credentialHash = authService.generateCredentialHash(credential)
userRepository.findByEmailAndIsEmailVerifiedTrueAndActiveTrue(oauth2UserResponse.email!!)?.let {
throw DuplicateEmailException(socialProvider)
}
userRepository.save(user)
return TokenResponse(token = user.credentialHash)
}

override suspend fun attachGoogle(
user: User,
socialLoginRequest: SocialLoginRequest,
): TokenResponse {
if (user.credential.googleSub != null) throw AlreadySocialAccountException
val token = socialLoginRequest.token
val oauth2UserResponse = authService.socialLoginWithAccessToken(SocialProvider.GOOGLE, token)

if (userRepository.existsByCredentialGoogleSubAndActiveTrue(oauth2UserResponse.socialId)) {
throw DuplicateSocialAccountException
when (socialProvider) {
SocialProvider.FACEBOOK -> {
if (user.credential.fbId != null) throw AlreadySocialAccountException
if (userRepository.existsByCredentialFbIdAndActiveTrue(oauth2UserResponse.socialId)) {
throw DuplicateSocialAccountException
}
val facebookCredential = authService.buildFacebookCredential(oauth2UserResponse)
user.credential.apply {
fbId = facebookCredential.fbId
fbName = facebookCredential.fbName
}
}
SocialProvider.GOOGLE -> {
if (user.credential.googleSub != null) throw AlreadySocialAccountException
if (userRepository.existsByCredentialGoogleSubAndActiveTrue(oauth2UserResponse.socialId)) {
throw DuplicateSocialAccountException
}
val googleCredential = authService.buildGoogleCredential(oauth2UserResponse)
user.credential.apply {
googleSub = googleCredential.googleSub
googleEmail = googleCredential.googleEmail
}
}
SocialProvider.KAKAO -> {
if (user.credential.kakaoSub != null) throw AlreadySocialAccountException
if (userRepository.existsByCredentialKakaoSubAndActiveTrue(oauth2UserResponse.socialId)) {
throw DuplicateSocialAccountException
}
val kakaoCredential = authService.buildKakaoCredential(oauth2UserResponse)
user.credential.apply {
kakaoSub = kakaoCredential.kakaoSub
kakaoEmail = kakaoCredential.kakaoEmail
}
}
else -> throw IllegalStateException("Unknown social provider")
}
val socialCredential = authService.buildGoogleCredential(oauth2UserResponse)

checkNotNull(oauth2UserResponse.email) { "google email is null: $oauth2UserResponse" }
userRepository.findByEmailAndIsEmailVerifiedTrueAndActiveTrue(oauth2UserResponse.email)?.let {
throw DuplicateEmailException(SocialProvider.GOOGLE)
}
user.apply {
credential.googleSub = socialCredential.googleSub
credential.googleEmail = socialCredential.googleEmail
credentialHash = authService.generateCredentialHash(credential)
}
user.credentialHash = authService.generateCredentialHash(user.credential)
userRepository.save(user)
return TokenResponse(token = user.credentialHash)
}

override suspend fun attachKakao(
override suspend fun detachSocial(
user: User,
socialLoginRequest: SocialLoginRequest,
socialProvider: SocialProvider,
): TokenResponse {
if (user.credential.kakaoSub != null) throw AlreadySocialAccountException
val token = socialLoginRequest.token
val oauth2UserResponse = authService.socialLoginWithAccessToken(SocialProvider.KAKAO, token)

if (userRepository.existsByCredentialKakaoSubAndActiveTrue(oauth2UserResponse.socialId)) {
throw DuplicateSocialAccountException
}
val socialCredential = authService.buildKakaoCredential(oauth2UserResponse)

checkNotNull(oauth2UserResponse.email) { "kakao email is null: $oauth2UserResponse" }
userRepository.findByEmailAndIsEmailVerifiedTrueAndActiveTrue(oauth2UserResponse.email)?.let {
throw DuplicateEmailException(SocialProvider.KAKAO)
}
user.apply {
credential.kakaoSub = socialCredential.kakaoSub
credential.kakaoEmail = socialCredential.kakaoEmail
credentialHash = authService.generateCredentialHash(credential)
}
userRepository.save(user)
return TokenResponse(token = user.credentialHash)
}

override suspend fun detachFacebook(user: User): TokenResponse {
getSocialProvider(user, filter = SocialProvider.FACEBOOK)
user.apply {
credential.fbId = null
credential.fbName = null
credentialHash = authService.generateCredentialHash(credential)
}
userRepository.save(user)
return TokenResponse(token = user.credentialHash)
}

override suspend fun detachGoogle(user: User): TokenResponse {
getSocialProvider(user, filter = SocialProvider.GOOGLE)
user.apply {
credential.googleSub = null
credential.googleEmail = null
credentialHash = authService.generateCredentialHash(credential)
}
userRepository.save(user)
return TokenResponse(token = user.credentialHash)
}

override suspend fun detachKakao(user: User): TokenResponse {
getSocialProvider(user, filter = SocialProvider.KAKAO)
user.apply {
credential.kakaoSub = null
credential.kakaoEmail = null
credentialHash = authService.generateCredentialHash(credential)
getSocialProvider(user, filter = socialProvider)
when (socialProvider) {
SocialProvider.FACEBOOK -> {
user.credential.apply {
fbId = null
fbName = null
}
}
SocialProvider.GOOGLE -> {
user.credential.apply {
googleSub = null
googleEmail = null
}
}
SocialProvider.KAKAO -> {
user.credential.apply {
kakaoSub = null
kakaoEmail = null
}
}
else -> throw IllegalStateException("Unknown social provider")
}
user.credentialHash = authService.generateCredentialHash(user.credential)
userRepository.save(user)
return TokenResponse(token = user.credentialHash)
}
Expand Down

0 comments on commit 6c05e77

Please sign in to comment.