Skip to content

Commit

Permalink
Merge pull request #232 from ahachulTeam/feature/229
Browse files Browse the repository at this point in the history
카카오, 구글 로그인 작동하도록 수정
  • Loading branch information
hwgyun authored Nov 2, 2024
2 parents eb8d3a7 + b3cf614 commit c82b415
Show file tree
Hide file tree
Showing 12 changed files with 104 additions and 68 deletions.
2 changes: 1 addition & 1 deletion ahachul_backend/ahachul_secret
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import backend.team.ahachul_backend.api.member.application.port.`in`.AuthUseCase
import backend.team.ahachul_backend.api.member.application.port.`in`.command.GetRedirectUrlCommand
import backend.team.ahachul_backend.api.member.domain.model.ProviderType
import backend.team.ahachul_backend.common.exception.CommonException
import backend.team.ahachul_backend.common.properties.OAuthProperties
import backend.team.ahachul_backend.common.response.CommonResponse
import backend.team.ahachul_backend.common.response.ResponseCode
import io.jsonwebtoken.ExpiredJwtException
Expand All @@ -18,21 +17,32 @@ import org.springframework.web.bind.annotation.*

@RestController
class AuthController(
private val authUseCase: AuthUseCase,

private val oAuthProperties: OAuthProperties,
private val authUseCase: AuthUseCase,
) {
fun verifyOrigin(origin: String?) {
if (origin == null) {
throw CommonException(ResponseCode.BAD_REQUEST)
}
}

@GetMapping("/v1/auth/redirect-url")
fun getRedirectUrl(@RequestParam providerType: ProviderType): CommonResponse<GetRedirectUrlDto.Response> {
return CommonResponse.success(authUseCase.getRedirectUrl(GetRedirectUrlCommand(providerType)))
fun getRedirectUrl(
@RequestHeader(value = "Origin") origin: String?,
@RequestParam providerType: ProviderType
): CommonResponse<GetRedirectUrlDto.Response> {
verifyOrigin(origin)

return CommonResponse.success(authUseCase.getRedirectUrl(GetRedirectUrlCommand(origin!!, providerType)))
}

@PostMapping("/v1/auth/login")
fun login(@RequestHeader(value="Origin") origin: String?, @RequestBody request: LoginMemberDto.Request): CommonResponse<LoginMemberDto.Response> {
// TODO 개발용 코드. 추후 삭제
oAuthProperties.client[request.providerType.toString().lowercase()]!!.redirectUri = "$origin/onboarding/redirect?type=${request.providerType}"
return CommonResponse.success(authUseCase.login(request.toCommand()))
fun login(
@RequestHeader(value = "Origin") origin: String?,
@RequestBody request: LoginMemberDto.Request
): CommonResponse<LoginMemberDto.Response> {
verifyOrigin(origin)

return CommonResponse.success(authUseCase.login(request.toCommand(origin!!)))
}

@PostMapping("/v1/auth/token/refresh")
Expand All @@ -41,7 +51,10 @@ class AuthController(
return CommonResponse.success(authUseCase.getToken(request.toCommand()))
} catch (e: Exception) {
throw when (e) {
is SignatureException, is UnsupportedJwtException, is IllegalArgumentException, is MalformedJwtException -> CommonException(ResponseCode.INVALID_REFRESH_TOKEN)
is SignatureException, is UnsupportedJwtException, is IllegalArgumentException, is MalformedJwtException -> CommonException(
ResponseCode.INVALID_REFRESH_TOKEN
)

is ExpiredJwtException -> CommonException(ResponseCode.EXPIRED_REFRESH_TOKEN)
else -> CommonException(ResponseCode.INTERNAL_SERVER_ERROR)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,9 @@ class LoginMemberDto {
@NotNull
val providerCode: String
) {
fun toCommand(): LoginMemberCommand {
fun toCommand(originHost:String): LoginMemberCommand {
return LoginMemberCommand(
originHost = originHost,
providerType = providerType,
providerCode = providerCode
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package backend.team.ahachul_backend.api.member.application.port.`in`.command
import backend.team.ahachul_backend.api.member.domain.model.ProviderType

class GetRedirectUrlCommand(
val originHost: String,
val providerType: ProviderType
) {
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package backend.team.ahachul_backend.api.member.application.port.`in`.command
import backend.team.ahachul_backend.api.member.domain.model.ProviderType

data class LoginMemberCommand(
val originHost: String,
val providerCode: String,
val providerType: ProviderType
) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,16 +24,16 @@ import org.springframework.web.util.UriComponentsBuilder
import java.util.*

@Service
@Transactional(readOnly=true)
@Transactional(readOnly = true)
class AuthService(
private val memberWriter: MemberWriter,
private val memberReader: MemberReader,
private val kakaoMemberClient: KakaoMemberClient,
private val googleMemberClient: GoogleMemberClient,
private val jwtUtils: JwtUtils,
private val jwtProperties: JwtProperties,
private val oAuthProperties: OAuthProperties,
): AuthUseCase {
private val memberWriter: MemberWriter,
private val memberReader: MemberReader,
private val kakaoMemberClient: KakaoMemberClient,
private val googleMemberClient: GoogleMemberClient,
private val jwtUtils: JwtUtils,
private val jwtProperties: JwtProperties,
private val oAuthProperties: OAuthProperties,
) : AuthUseCase {

companion object {
const val sevenDaysInMillis = 7 * 24 * 60 * 60 * 1000
Expand All @@ -44,13 +44,22 @@ class AuthService(
var isDuplicatedNickname = false
val member = when (command.providerType) {
ProviderType.KAKAO -> {
val userInfo = getKakaoMemberInfo(command.providerCode)
val userInfo = getKakaoMemberInfo(
command.providerCode,
getRedirectUriByOrigin(command.originHost, ProviderType.KAKAO)
)
val member = memberReader.findMember(userInfo.id)
userInfo.kakaoAccount.profile?.let { profile -> isDuplicatedNickname = memberReader.existMember(profile.nickname) }
userInfo.kakaoAccount.profile?.let { profile ->
isDuplicatedNickname = memberReader.existMember(profile.nickname)
}
member ?: memberWriter.save(MemberEntity.ofKakao(command, userInfo))
}

ProviderType.GOOGLE -> {
val userInfo = getGoogleMemberInfo(command.providerCode)
val userInfo = getGoogleMemberInfo(
command.providerCode,
getRedirectUriByOrigin(command.originHost, ProviderType.GOOGLE)
)
val member = memberReader.findMember(userInfo.id)
isDuplicatedNickname = memberReader.existMember(userInfo.name)
member ?: memberWriter.save(MemberEntity.ofGoogle(command, userInfo))
Expand All @@ -59,66 +68,77 @@ class AuthService(
return makeLoginResponse(member.id.toString(), member.isNeedAdditionalUserInfo() || isDuplicatedNickname)
}

private fun getKakaoMemberInfo(provideCode: String): KakaoMemberInfoDto {
val accessToken = kakaoMemberClient.getAccessTokenByCode(provideCode)
private fun getKakaoMemberInfo(provideCode: String, redirectUri: String): KakaoMemberInfoDto {
val accessToken = kakaoMemberClient.getAccessTokenByCode(provideCode, redirectUri)
return kakaoMemberClient.getMemberInfoByAccessToken(accessToken)
}

private fun getGoogleMemberInfo(provideCode: String): GoogleUserInfoDto {
val accessToken = googleMemberClient.getAccessTokenByCode(provideCode)
private fun getGoogleMemberInfo(provideCode: String, redirectUri: String): GoogleUserInfoDto {
val accessToken = googleMemberClient.getAccessTokenByCode(provideCode, redirectUri)
return googleMemberClient.getMemberInfoByAccessToken(accessToken)
}

private fun makeLoginResponse(memberId: String, isNeedAdditionalUserInfo: Boolean): LoginMemberDto.Response {
return LoginMemberDto.Response(
memberId = memberId,
isNeedAdditionalUserInfo = isNeedAdditionalUserInfo,
accessToken = jwtUtils.createToken(memberId, jwtProperties.accessTokenExpireTime),
accessTokenExpiresIn = jwtProperties.accessTokenExpireTime,
refreshToken = jwtUtils.createToken(memberId, jwtProperties.refreshTokenExpireTime),
refreshTokenExpiresIn = jwtProperties.refreshTokenExpireTime
memberId = memberId,
isNeedAdditionalUserInfo = isNeedAdditionalUserInfo,
accessToken = jwtUtils.createToken(memberId, jwtProperties.accessTokenExpireTime),
accessTokenExpiresIn = jwtProperties.accessTokenExpireTime,
refreshToken = jwtUtils.createToken(memberId, jwtProperties.refreshTokenExpireTime),
refreshTokenExpiresIn = jwtProperties.refreshTokenExpireTime
)
}

override fun getToken(command: GetTokenCommand): GetTokenDto.Response {
val refreshToken = jwtUtils.verify(command.refreshToken)

if (refreshToken.body.expiration.after(Date(System.currentTimeMillis() - sevenDaysInMillis))) {
return GetTokenDto.Response (
accessToken = jwtUtils.createToken(refreshToken.body.subject, jwtProperties.accessTokenExpireTime),
accessTokenExpiresIn = jwtProperties.accessTokenExpireTime,
refreshToken = jwtUtils.createToken(refreshToken.body.subject, jwtProperties.refreshTokenExpireTime),
refreshTokenExpiresIn = jwtProperties.refreshTokenExpireTime
return GetTokenDto.Response(
accessToken = jwtUtils.createToken(refreshToken.body.subject, jwtProperties.accessTokenExpireTime),
accessTokenExpiresIn = jwtProperties.accessTokenExpireTime,
refreshToken = jwtUtils.createToken(refreshToken.body.subject, jwtProperties.refreshTokenExpireTime),
refreshTokenExpiresIn = jwtProperties.refreshTokenExpireTime
)
}
return GetTokenDto.Response (
return GetTokenDto.Response(
accessToken = jwtUtils.createToken(refreshToken.body.subject, jwtProperties.accessTokenExpireTime),
accessTokenExpiresIn = jwtProperties.accessTokenExpireTime
)
}

private fun getRedirectUriByOrigin(originHost: String, providerType: ProviderType): String {
val providerTypeStr = providerType.toString().lowercase()
val client = oAuthProperties.client[providerTypeStr]!!

return if (originHost.endsWith("/")) "$originHost${client.redirectUriPath}" else "$originHost/${client.redirectUriPath}"
}

override fun getRedirectUrl(command: GetRedirectUrlCommand): GetRedirectUrlDto.Response {
val providerTypeStr = command.providerType.toString().lowercase()
val client = oAuthProperties.client[providerTypeStr]!!
val provider = oAuthProperties.provider[providerTypeStr]!!

val redirectUri = getRedirectUriByOrigin(command.originHost, command.providerType)

return GetRedirectUrlDto.Response(
when (command.providerType) {
ProviderType.KAKAO -> UriComponentsBuilder.fromUriString(provider.loginUri)
.queryParam("client_id", client.clientId)
.queryParam("redirect_uri", client.redirectUri)
.queryParam("response_type", client.responseType)
.build()
.toString()
.queryParam("client_id", client.clientId)
.queryParam("redirect_uri", redirectUri)
.queryParam("response_type", client.responseType)
.build()
.toString()

ProviderType.GOOGLE -> UriComponentsBuilder.fromUriString(provider.loginUri)
.queryParam("client_id", client.clientId)
.queryParam("redirect_uri", client.redirectUri)
.queryParam("access_type", client.accessType)
.queryParam("response_type", client.responseType)
.queryParam("scope", client.scope)
.build()
.toString()
})
.queryParam("client_id", client.clientId)
.queryParam("redirect_uri", redirectUri)
.queryParam("access_type", client.accessType)
.queryParam("response_type", client.responseType)
.queryParam("scope", client.scope)
.build()
.toString()
}
)
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import backend.team.ahachul_backend.common.dto.GoogleUserInfoDto

interface GoogleMemberClient {

fun getAccessTokenByCode(code: String): String
fun getAccessTokenByCode(code: String, redirectUri: String): String

fun getMemberInfoByAccessToken(accessToken: String): GoogleUserInfoDto
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import backend.team.ahachul_backend.common.dto.KakaoMemberInfoDto

interface KakaoMemberClient {

fun getAccessTokenByCode(code: String): String
fun getAccessTokenByCode(code: String, redirectUri: String): String

fun getMemberInfoByAccessToken(accessToken: String): KakaoMemberInfoDto
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,11 @@ class GoogleMemberClientImpl(
private val provider :OAuthProperties.Provider = oAuthProperties.provider[PROVIDER]!!
val objectMapper: ObjectMapper = ObjectMapper()

override fun getAccessTokenByCode(code: String): String {
override fun getAccessTokenByCode(code: String, redirectUri: String): String {
val headers = HttpHeaders().apply {
contentType = MediaType.APPLICATION_FORM_URLENCODED
}
val httpEntity = HttpEntity(getHttpBodyParams(code), headers)
val httpEntity = HttpEntity(getHttpBodyParams(code, redirectUri), headers)
val response = restTemplate.exchange(provider.tokenUri, HttpMethod.POST, httpEntity, String::class.java)

if (response.statusCode == HttpStatus.OK) {
Expand All @@ -40,12 +40,12 @@ class GoogleMemberClientImpl(
throw CommonException(ResponseCode.INVALID_OAUTH_AUTHORIZATION_CODE)
}

private fun getHttpBodyParams(code: String): LinkedMultiValueMap<String, String?>{
private fun getHttpBodyParams(code: String, redirectUri: String): LinkedMultiValueMap<String, String?>{
val params = LinkedMultiValueMap<String, String?>()
params["code"] = code
params["client_id"] = client.clientId
params["client_secret"] = client.clientSecret
params["redirect_uri"] = client.redirectUri
params["redirect_uri"] = redirectUri
params["grant_type"] = "authorization_code"
return params
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,15 @@ class KakaoMemberClientImpl(
private val oAuthProperties: OAuthProperties
): KakaoMemberClient {

override fun getAccessTokenByCode(code: String): String {
override fun getAccessTokenByCode(code: String, redirectUri: String): String {
val headers = HttpHeaders().apply {
contentType = MediaType.APPLICATION_FORM_URLENCODED
}

val params = LinkedMultiValueMap<String, String>()
params.add("grant_type", "authorization_code")
params.add("client_id", oAuthProperties.client["kakao"]!!.clientId)
params.add("redirect_uri", oAuthProperties.client["kakao"]!!.redirectUri)
params.add("redirect_uri", redirectUri)
params.add("code", code)

val request = HttpEntity(params, headers)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@ package backend.team.ahachul_backend.common.dto

import com.fasterxml.jackson.annotation.JsonProperty

data class GoogleUserInfoDto (
data class GoogleUserInfoDto(
@JsonProperty("id") val id: String,
@JsonProperty("email") val email: String,
@JsonProperty("verified_email") val verifiedEmail: Boolean,
@JsonProperty("name") val name: String,
@JsonProperty("given_name") val givenName: String,
@JsonProperty("family_name") val familyName: String,
@JsonProperty("picture") val picture: String,
@JsonProperty("locale") val locale: String
@JsonProperty("given_name") val givenName: String?,
@JsonProperty("family_name") val familyName: String?,
@JsonProperty("picture") val picture: String?,
@JsonProperty("locale") val locale: String?
)
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ class OAuthProperties(
data class Client(
val clientId: String,
val clientSecret: String?,
var redirectUri: String,
var redirectUriPath: String,
val scope: String?,
val responseType: String,
val accessType: String?
Expand Down

0 comments on commit c82b415

Please sign in to comment.