diff --git a/ahachul_backend/ahachul_secret b/ahachul_backend/ahachul_secret index dec1b30e..e6bfabb9 160000 --- a/ahachul_backend/ahachul_secret +++ b/ahachul_backend/ahachul_secret @@ -1 +1 @@ -Subproject commit dec1b30eaf1741b2c644e19ae6c09e9beeee38d5 +Subproject commit e6bfabb980c1aea4dd449fb04f0687c5e420bffa diff --git a/ahachul_backend/src/main/kotlin/backend/team/ahachul_backend/api/member/adapter/web/in/AuthController.kt b/ahachul_backend/src/main/kotlin/backend/team/ahachul_backend/api/member/adapter/web/in/AuthController.kt index e69bc6aa..13301ac3 100644 --- a/ahachul_backend/src/main/kotlin/backend/team/ahachul_backend/api/member/adapter/web/in/AuthController.kt +++ b/ahachul_backend/src/main/kotlin/backend/team/ahachul_backend/api/member/adapter/web/in/AuthController.kt @@ -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 @@ -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 { - return CommonResponse.success(authUseCase.getRedirectUrl(GetRedirectUrlCommand(providerType))) + fun getRedirectUrl( + @RequestHeader(value = "Origin") origin: String?, + @RequestParam providerType: ProviderType + ): CommonResponse { + 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 { - // 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 { + verifyOrigin(origin) + + return CommonResponse.success(authUseCase.login(request.toCommand(origin!!))) } @PostMapping("/v1/auth/token/refresh") @@ -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) } diff --git a/ahachul_backend/src/main/kotlin/backend/team/ahachul_backend/api/member/adapter/web/in/dto/LoginMemberDto.kt b/ahachul_backend/src/main/kotlin/backend/team/ahachul_backend/api/member/adapter/web/in/dto/LoginMemberDto.kt index 2a00d527..7692445f 100644 --- a/ahachul_backend/src/main/kotlin/backend/team/ahachul_backend/api/member/adapter/web/in/dto/LoginMemberDto.kt +++ b/ahachul_backend/src/main/kotlin/backend/team/ahachul_backend/api/member/adapter/web/in/dto/LoginMemberDto.kt @@ -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 ) diff --git a/ahachul_backend/src/main/kotlin/backend/team/ahachul_backend/api/member/application/port/in/command/GetRedirectUrlCommand.kt b/ahachul_backend/src/main/kotlin/backend/team/ahachul_backend/api/member/application/port/in/command/GetRedirectUrlCommand.kt index 734aa9de..cc2031c3 100644 --- a/ahachul_backend/src/main/kotlin/backend/team/ahachul_backend/api/member/application/port/in/command/GetRedirectUrlCommand.kt +++ b/ahachul_backend/src/main/kotlin/backend/team/ahachul_backend/api/member/application/port/in/command/GetRedirectUrlCommand.kt @@ -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 ) { } \ No newline at end of file diff --git a/ahachul_backend/src/main/kotlin/backend/team/ahachul_backend/api/member/application/port/in/command/LoginMemberCommand.kt b/ahachul_backend/src/main/kotlin/backend/team/ahachul_backend/api/member/application/port/in/command/LoginMemberCommand.kt index c7b3aedc..75c95625 100644 --- a/ahachul_backend/src/main/kotlin/backend/team/ahachul_backend/api/member/application/port/in/command/LoginMemberCommand.kt +++ b/ahachul_backend/src/main/kotlin/backend/team/ahachul_backend/api/member/application/port/in/command/LoginMemberCommand.kt @@ -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 ) { diff --git a/ahachul_backend/src/main/kotlin/backend/team/ahachul_backend/api/member/application/service/AuthService.kt b/ahachul_backend/src/main/kotlin/backend/team/ahachul_backend/api/member/application/service/AuthService.kt index a22f0be0..8bd0c817 100644 --- a/ahachul_backend/src/main/kotlin/backend/team/ahachul_backend/api/member/application/service/AuthService.kt +++ b/ahachul_backend/src/main/kotlin/backend/team/ahachul_backend/api/member/application/service/AuthService.kt @@ -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 @@ -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)) @@ -59,24 +68,24 @@ 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 ) } @@ -84,41 +93,52 @@ class AuthService( 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() + } + ) } } diff --git a/ahachul_backend/src/main/kotlin/backend/team/ahachul_backend/common/client/GoogleMemberClient.kt b/ahachul_backend/src/main/kotlin/backend/team/ahachul_backend/common/client/GoogleMemberClient.kt index 3a3cadd1..8def208f 100644 --- a/ahachul_backend/src/main/kotlin/backend/team/ahachul_backend/common/client/GoogleMemberClient.kt +++ b/ahachul_backend/src/main/kotlin/backend/team/ahachul_backend/common/client/GoogleMemberClient.kt @@ -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 } \ No newline at end of file diff --git a/ahachul_backend/src/main/kotlin/backend/team/ahachul_backend/common/client/KakaoMemberClient.kt b/ahachul_backend/src/main/kotlin/backend/team/ahachul_backend/common/client/KakaoMemberClient.kt index 933e02b3..e1fdd7ae 100644 --- a/ahachul_backend/src/main/kotlin/backend/team/ahachul_backend/common/client/KakaoMemberClient.kt +++ b/ahachul_backend/src/main/kotlin/backend/team/ahachul_backend/common/client/KakaoMemberClient.kt @@ -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 } \ No newline at end of file diff --git a/ahachul_backend/src/main/kotlin/backend/team/ahachul_backend/common/client/impl/GoogleMemberClientImpl.kt b/ahachul_backend/src/main/kotlin/backend/team/ahachul_backend/common/client/impl/GoogleMemberClientImpl.kt index 9624404f..ce6ff1aa 100644 --- a/ahachul_backend/src/main/kotlin/backend/team/ahachul_backend/common/client/impl/GoogleMemberClientImpl.kt +++ b/ahachul_backend/src/main/kotlin/backend/team/ahachul_backend/common/client/impl/GoogleMemberClientImpl.kt @@ -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) { @@ -40,12 +40,12 @@ class GoogleMemberClientImpl( throw CommonException(ResponseCode.INVALID_OAUTH_AUTHORIZATION_CODE) } - private fun getHttpBodyParams(code: String): LinkedMultiValueMap{ + private fun getHttpBodyParams(code: String, redirectUri: String): LinkedMultiValueMap{ val params = LinkedMultiValueMap() 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 } diff --git a/ahachul_backend/src/main/kotlin/backend/team/ahachul_backend/common/client/impl/KakaoMemberClientImpl.kt b/ahachul_backend/src/main/kotlin/backend/team/ahachul_backend/common/client/impl/KakaoMemberClientImpl.kt index 1979e1f9..19ed12d4 100644 --- a/ahachul_backend/src/main/kotlin/backend/team/ahachul_backend/common/client/impl/KakaoMemberClientImpl.kt +++ b/ahachul_backend/src/main/kotlin/backend/team/ahachul_backend/common/client/impl/KakaoMemberClientImpl.kt @@ -24,7 +24,7 @@ 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 } @@ -32,7 +32,7 @@ class KakaoMemberClientImpl( val params = LinkedMultiValueMap() 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) diff --git a/ahachul_backend/src/main/kotlin/backend/team/ahachul_backend/common/dto/GoogleUserInfoDto.kt b/ahachul_backend/src/main/kotlin/backend/team/ahachul_backend/common/dto/GoogleUserInfoDto.kt index 77e03bd7..ae53d90a 100644 --- a/ahachul_backend/src/main/kotlin/backend/team/ahachul_backend/common/dto/GoogleUserInfoDto.kt +++ b/ahachul_backend/src/main/kotlin/backend/team/ahachul_backend/common/dto/GoogleUserInfoDto.kt @@ -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? ) \ No newline at end of file diff --git a/ahachul_backend/src/main/kotlin/backend/team/ahachul_backend/common/properties/OAuthProperties.kt b/ahachul_backend/src/main/kotlin/backend/team/ahachul_backend/common/properties/OAuthProperties.kt index c469b817..a9cf72a1 100644 --- a/ahachul_backend/src/main/kotlin/backend/team/ahachul_backend/common/properties/OAuthProperties.kt +++ b/ahachul_backend/src/main/kotlin/backend/team/ahachul_backend/common/properties/OAuthProperties.kt @@ -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?