diff --git a/api/src/main/kotlin/com/oksusu/susu/api/auth/application/AuthFacade.kt b/api/src/main/kotlin/com/oksusu/susu/api/auth/application/AuthFacade.kt index 041ddaa9..cc06ca44 100644 --- a/api/src/main/kotlin/com/oksusu/susu/api/auth/application/AuthFacade.kt +++ b/api/src/main/kotlin/com/oksusu/susu/api/auth/application/AuthFacade.kt @@ -27,6 +27,7 @@ import com.oksusu.susu.domain.user.domain.UserWithdraw import com.oksusu.susu.domain.user.domain.vo.AccountRole import com.oksusu.susu.domain.user.domain.vo.UserStatusAssignmentType import com.oksusu.susu.domain.user.domain.vo.UserStatusTypeInfo +import io.github.oshai.kotlinlogging.KotlinLogging import kotlinx.coroutines.async import kotlinx.coroutines.awaitAll import kotlinx.coroutines.coroutineScope @@ -47,6 +48,8 @@ class AuthFacade( private val txTemplates: TransactionTemplates, private val userStatusTypeService: UserStatusTypeService, ) { + val logger = KotlinLogging.logger { } + fun resolveAuthUser(token: Mono): Mono { return jwtTokenService.verifyTokenMono(token) .map { payload -> @@ -70,7 +73,7 @@ class AuthFacade( } private fun raiseIf(userStatus: UserStatus): UserStatusTypeModel { - val userStatusType = userStatusTypeService.getStatus(userStatus.id) + val userStatusType = userStatusTypeService.getStatus(userStatus.accountStatusId) /** status type에 따른 처리 */ when (userStatusType.statusTypeInfo) { diff --git a/api/src/main/kotlin/com/oksusu/susu/api/auth/application/OAuthFacade.kt b/api/src/main/kotlin/com/oksusu/susu/api/auth/application/OAuthFacade.kt index 911ca63b..ca457582 100644 --- a/api/src/main/kotlin/com/oksusu/susu/api/auth/application/OAuthFacade.kt +++ b/api/src/main/kotlin/com/oksusu/susu/api/auth/application/OAuthFacade.kt @@ -4,6 +4,7 @@ import com.oksusu.susu.api.auth.model.AuthUser import com.oksusu.susu.api.auth.model.TokenDto import com.oksusu.susu.api.auth.model.request.OAuthLoginRequest import com.oksusu.susu.api.auth.model.request.OAuthRegisterRequest +import com.oksusu.susu.api.auth.model.request.OidcLoginRequest import com.oksusu.susu.api.auth.model.response.AbleRegisterResponse import com.oksusu.susu.api.auth.model.response.UserOAuthInfoResponse import com.oksusu.susu.api.event.model.CreateUserDeviceEvent @@ -28,6 +29,7 @@ import com.oksusu.susu.domain.user.domain.UserStatus import com.oksusu.susu.domain.user.domain.UserStatusHistory import com.oksusu.susu.domain.user.domain.vo.AccountRole import com.oksusu.susu.domain.user.domain.vo.OAuthProvider +import com.oksusu.susu.domain.user.domain.vo.OauthInfo import com.oksusu.susu.domain.user.domain.vo.UserStatusAssignmentType import io.github.oshai.kotlinlogging.KotlinLogging import kotlinx.coroutines.Dispatchers @@ -54,17 +56,33 @@ class OAuthFacade( ) { val logger = KotlinLogging.logger {} - /** 회원가입 가능 여부 체크. */ - suspend fun checkRegisterValid(provider: OAuthProvider, accessToken: String): AbleRegisterResponse { + /** OAuth 회원가입 가능 여부 체크. */ + suspend fun checkRegisterValidWithOAuth(provider: OAuthProvider, accessToken: String): AbleRegisterResponse { val oauthInfo = oAuthService.getOAuthInfo(provider, accessToken) + return checkRegisterValid(oauthInfo) + } + + /** Oidc 회원가입 가능 여부 체크. */ + suspend fun checkRegisterValidWithOidc(provider: OAuthProvider, idToken: String): AbleRegisterResponse { + val oauthInfo = oAuthService.getOAuthInfoWithOidc(provider, idToken) + + return checkRegisterValid(oauthInfo) + } + + /** + * 회원가입 가능 여부 체크 공통 로직 + */ + private suspend fun checkRegisterValid(oauthInfo: OauthInfo): AbleRegisterResponse { + val isExistUser = userService.existsByOAuthInfo(oauthInfo) return AbleRegisterResponse(!isExistUser) + } - /** 회원가입 */ - suspend fun register( + /** OAuth 회원가입 */ + suspend fun registerWithOAuth( provider: OAuthProvider, accessToken: String, request: OAuthRegisterRequest, @@ -74,6 +92,31 @@ class OAuthFacade( val oauthInfo = oAuthService.getOAuthInfo(provider, accessToken) + return register(oauthInfo, request, deviceContext) + } + + /** Oidc 회원가입 */ + suspend fun registerWithOidc( + provider: OAuthProvider, + idToken: String, + request: OAuthRegisterRequest, + deviceContext: UserDeviceContext, + ): TokenDto { + authValidateService.validateRegisterRequest(request) + + val oauthInfo = oAuthService.getOAuthInfoWithOidc(provider, idToken) + + return register(oauthInfo, request, deviceContext) + } + + /** + * 회원가입 공통 로직 + */ + private suspend fun register( + oauthInfo: OauthInfo, + request: OAuthRegisterRequest, + deviceContext: UserDeviceContext, + ): TokenDto { coroutineScope { val validateNotRegistered = async(Dispatchers.IO) { userService.validateNotRegistered( @@ -149,13 +192,32 @@ class OAuthFacade( return generateTokenDto(user.id) } - /** 로그인 */ - suspend fun login( + /** OAuth 로그인 */ + suspend fun loginWithOAuth( provider: OAuthProvider, request: OAuthLoginRequest, deviceContext: UserDeviceContext, ): TokenDto { val oauthInfo = oAuthService.getOAuthInfo(provider, request.accessToken) + + return login(oauthInfo, deviceContext) + } + + /** Oidc 로그인 */ + suspend fun loginWithOidc( + provider: OAuthProvider, + request: OidcLoginRequest, + deviceContext: UserDeviceContext, + ): TokenDto { + val oauthInfo = oAuthService.getOAuthInfoWithOidc(provider, request.idToken) + + return login(oauthInfo, deviceContext) + } + + /** + * 회원가입 공통 로직 + */ + private suspend fun login(oauthInfo: OauthInfo, deviceContext: UserDeviceContext): TokenDto { val user = userService.findByOAuthInfoOrThrow(oauthInfo) val userDevice = UserDevice( diff --git a/api/src/main/kotlin/com/oksusu/susu/api/auth/application/OAuthService.kt b/api/src/main/kotlin/com/oksusu/susu/api/auth/application/OAuthService.kt index f53e4ec6..18a0a249 100644 --- a/api/src/main/kotlin/com/oksusu/susu/api/auth/application/OAuthService.kt +++ b/api/src/main/kotlin/com/oksusu/susu/api/auth/application/OAuthService.kt @@ -5,6 +5,8 @@ import com.oksusu.susu.api.auth.application.oauth.GoogleOAuthService import com.oksusu.susu.api.auth.application.oauth.KakaoOAuthService import com.oksusu.susu.api.auth.model.response.OAuthLoginLinkResponse import com.oksusu.susu.api.auth.model.response.OAuthTokenResponse +import com.oksusu.susu.common.exception.ErrorCode +import com.oksusu.susu.common.exception.InvalidRequestException import com.oksusu.susu.domain.user.domain.vo.OAuthProvider import com.oksusu.susu.domain.user.domain.vo.OauthInfo import io.github.oshai.kotlinlogging.KotlinLogging @@ -51,6 +53,17 @@ class OAuthService( }.oauthInfo } + /** oauth info 가져오기 */ + suspend fun getOAuthInfoWithOidc( + provider: OAuthProvider, + idToken: String, + ): OauthInfo { + return when (provider) { + OAuthProvider.GOOGLE -> googleOAuthService.getOAuthInfoWithOidc(idToken) + else -> throw InvalidRequestException(ErrorCode.INVALID_OAUTH_PROVIDER) + }.oauthInfo + } + /** oauth 유저 회원 탈퇴하기 */ suspend fun withdraw(oauthInfo: OauthInfo, code: String?, accessToken: String?) { when (oauthInfo.oAuthProvider) { diff --git a/api/src/main/kotlin/com/oksusu/susu/api/auth/application/oauth/GoogleOAuthService.kt b/api/src/main/kotlin/com/oksusu/susu/api/auth/application/oauth/GoogleOAuthService.kt index 0a605de3..3a429eff 100644 --- a/api/src/main/kotlin/com/oksusu/susu/api/auth/application/oauth/GoogleOAuthService.kt +++ b/api/src/main/kotlin/com/oksusu/susu/api/auth/application/oauth/GoogleOAuthService.kt @@ -1,12 +1,15 @@ package com.oksusu.susu.api.auth.application.oauth import com.oksusu.susu.api.auth.model.OAuthUserInfoDto +import com.oksusu.susu.api.auth.model.OidcDecodePayload import com.oksusu.susu.api.auth.model.response.OAuthLoginLinkResponse import com.oksusu.susu.api.auth.model.response.OAuthTokenResponse import com.oksusu.susu.api.config.OAuthSecretConfig import com.oksusu.susu.client.config.OAuthUrlConfig import com.oksusu.susu.client.oauth.google.GoogleClient import com.oksusu.susu.common.extension.withMDCContext +import com.oksusu.susu.domain.user.domain.vo.OAuthProvider +import com.oksusu.susu.domain.user.domain.vo.OauthInfo import io.github.oshai.kotlinlogging.KotlinLogging import kotlinx.coroutines.Dispatchers import org.springframework.beans.factory.annotation.Value @@ -17,6 +20,7 @@ class GoogleOAuthService( val googleOAuthUrlConfig: OAuthUrlConfig.GoogleOAuthUrlConfig, val googleOAuthSecretConfig: OAuthSecretConfig.GoogleOAuthSecretConfig, val googleClient: GoogleClient, + val oidcService: OidcService, @Value("\${server.domain-name}") private val domainName: String, ) { @@ -67,7 +71,10 @@ class GoogleOAuthService( clientId = googleOAuthSecretConfig.clientId, clientSecret = googleOAuthSecretConfig.clientSecret ) - }.run { OAuthTokenResponse.fromGoogle(this) } + }.run { + logger.info { this.idToken } + OAuthTokenResponse.fromGoogle(this) + } } /** 유저 정보를 가져옵니다. */ @@ -77,10 +84,36 @@ class GoogleOAuthService( }.run { OAuthUserInfoDto.fromGoogle(this) } } + + /** 유저 정보를 가져옵니다. */ + suspend fun getOAuthInfoWithOidc(idToken: String): OAuthUserInfoDto { + return withMDCContext(Dispatchers.IO) { + getOIDCDecodePayload(idToken) + }.run { OAuthUserInfoDto( + oauthInfo = OauthInfo( + oAuthProvider = OAuthProvider.GOOGLE, + oAuthId = this.sub + ) + ) } + } + /** 회원 탈퇴합니다 */ suspend fun withdraw(accessToken: String) { withMDCContext(Dispatchers.IO) { googleClient.withdraw(accessToken = accessToken) } } + + /** + * oidc decode + */ + private suspend fun getOIDCDecodePayload(token: String): OidcDecodePayload { + val oidcPublicKeysResponse = oidcService.getOidcPublicKeys(OAuthProvider.GOOGLE) + return oidcService.getPayloadFromIdToken( + token, + googleOAuthUrlConfig.accountGoogleUrl, + googleOAuthSecretConfig.clientId, + oidcPublicKeysResponse + ) + } } diff --git a/api/src/main/kotlin/com/oksusu/susu/api/auth/application/oauth/OidcService.kt b/api/src/main/kotlin/com/oksusu/susu/api/auth/application/oauth/OidcService.kt index d58d7fe6..3ce5a4fa 100644 --- a/api/src/main/kotlin/com/oksusu/susu/api/auth/application/oauth/OidcService.kt +++ b/api/src/main/kotlin/com/oksusu/susu/api/auth/application/oauth/OidcService.kt @@ -10,9 +10,11 @@ import com.oksusu.susu.cache.model.OidcPublicKeysCacheModel import com.oksusu.susu.cache.model.vo.OidcPublicKeyCacheModel import com.oksusu.susu.cache.service.CacheService import com.oksusu.susu.client.oauth.apple.AppleClient +import com.oksusu.susu.client.oauth.google.GoogleClient import com.oksusu.susu.client.oauth.oidc.model.OidcPublicKeyModel import com.oksusu.susu.client.oauth.oidc.model.OidcPublicKeysResponse import com.oksusu.susu.common.exception.ErrorCode +import com.oksusu.susu.common.exception.InvalidRequestException import com.oksusu.susu.common.exception.InvalidTokenException import com.oksusu.susu.common.extension.withMDCContext import com.oksusu.susu.domain.user.domain.vo.OAuthProvider @@ -31,6 +33,7 @@ import java.util.Date class OidcService( private val cacheService: CacheService, private val appleClient: AppleClient, + private val googleClient: GoogleClient, private val eventPublisher: ApplicationEventPublisher, ) { private val logger = KotlinLogging.logger { } @@ -39,10 +42,11 @@ class OidcService( withMDCContext(Dispatchers.IO) { when (provider) { OAuthProvider.APPLE -> cacheService.getOrNull(Cache.getAppleOidcPublicKeyCache()) - else -> null + OAuthProvider.GOOGLE -> cacheService.getOrNull(Cache.getGoogleOidcPublicKeyCache()) + else -> throw InvalidRequestException(ErrorCode.INVALID_OAUTH_PROVIDER) } }?.run { - logger.debug { "apple oidc public key cache hit" } + logger.debug { "oidc public key cache hit" } val models = this.keys.map { key -> OidcPublicKeyModel( @@ -58,7 +62,11 @@ class OidcService( } return withMDCContext(Dispatchers.IO) { - appleClient.getOidcPublicKeys() + when (provider) { + OAuthProvider.APPLE -> appleClient.getOidcPublicKeys() + OAuthProvider.GOOGLE -> googleClient.getOidcPublicKeys() + else -> throw InvalidRequestException(ErrorCode.INVALID_OAUTH_PROVIDER) + } }.run { val cachekeys = this.keys.map { key -> OidcPublicKeyCacheModel( @@ -92,11 +100,13 @@ class OidcService( verifyToken(jwt, iss, aud) + logger.info { jwt.claims } + return OidcDecodePayload( iss = jwt.getClaim("iss").asString(), aud = jwt.getClaim("aud").asString(), sub = jwt.getClaim("sub").asString(), - email = jwt.getClaim("email").asString() + email = jwt.getClaim("email")?.asString() ?: "" ) } diff --git a/api/src/main/kotlin/com/oksusu/susu/api/auth/model/AdminUser.kt b/api/src/main/kotlin/com/oksusu/susu/api/auth/model/AdminUser.kt index 2d943481..b74fa329 100644 --- a/api/src/main/kotlin/com/oksusu/susu/api/auth/model/AdminUser.kt +++ b/api/src/main/kotlin/com/oksusu/susu/api/auth/model/AdminUser.kt @@ -17,7 +17,7 @@ interface AdminUser { fun isNotAuthorThrow(uid: Long) } -class AdminUserImpl( +data class AdminUserImpl( override val uid: Long, ) : AdminUser { override fun isAuthor(uid: Long): Boolean { diff --git a/api/src/main/kotlin/com/oksusu/susu/api/auth/model/OAuthUserInfoDto.kt b/api/src/main/kotlin/com/oksusu/susu/api/auth/model/OAuthUserInfoDto.kt index 839ace90..262f20a7 100644 --- a/api/src/main/kotlin/com/oksusu/susu/api/auth/model/OAuthUserInfoDto.kt +++ b/api/src/main/kotlin/com/oksusu/susu/api/auth/model/OAuthUserInfoDto.kt @@ -6,7 +6,7 @@ import com.oksusu.susu.domain.user.domain.vo.OAuthProvider import com.oksusu.susu.domain.user.domain.vo.OauthInfo /** oauth 정보 dto */ -class OAuthUserInfoDto( +data class OAuthUserInfoDto( /** oauth 정보 */ val oauthInfo: OauthInfo, ) { diff --git a/api/src/main/kotlin/com/oksusu/susu/api/auth/model/OidcDecodePayload.kt b/api/src/main/kotlin/com/oksusu/susu/api/auth/model/OidcDecodePayload.kt index b0242f34..2fb4b488 100644 --- a/api/src/main/kotlin/com/oksusu/susu/api/auth/model/OidcDecodePayload.kt +++ b/api/src/main/kotlin/com/oksusu/susu/api/auth/model/OidcDecodePayload.kt @@ -1,6 +1,6 @@ package com.oksusu.susu.api.auth.model -class OidcDecodePayload( +data class OidcDecodePayload( /** issuer ex https://kauth.kakao.com */ val iss: String, /** client id */ @@ -8,4 +8,5 @@ class OidcDecodePayload( /** oauth provider account unique id */ val sub: String, val email: String, +// val profile: ) diff --git a/api/src/main/kotlin/com/oksusu/susu/api/auth/model/TokenDto.kt b/api/src/main/kotlin/com/oksusu/susu/api/auth/model/TokenDto.kt index 10947307..8780dfde 100644 --- a/api/src/main/kotlin/com/oksusu/susu/api/auth/model/TokenDto.kt +++ b/api/src/main/kotlin/com/oksusu/susu/api/auth/model/TokenDto.kt @@ -3,7 +3,7 @@ package com.oksusu.susu.api.auth.model import java.time.LocalDateTime /** 토큰 정보 dto */ -class TokenDto( +data class TokenDto( /** access token */ val accessToken: String, /** access token 유효기간 */ diff --git a/api/src/main/kotlin/com/oksusu/susu/api/auth/model/request/OAuthLoginRequest.kt b/api/src/main/kotlin/com/oksusu/susu/api/auth/model/request/OAuthLoginRequest.kt index c309187d..e0bb5efc 100644 --- a/api/src/main/kotlin/com/oksusu/susu/api/auth/model/request/OAuthLoginRequest.kt +++ b/api/src/main/kotlin/com/oksusu/susu/api/auth/model/request/OAuthLoginRequest.kt @@ -1,6 +1,6 @@ package com.oksusu.susu.api.auth.model.request -class OAuthLoginRequest( +data class OAuthLoginRequest( /** oauth access token */ val accessToken: String, ) diff --git a/api/src/main/kotlin/com/oksusu/susu/api/auth/model/request/OAuthRegisterRequest.kt b/api/src/main/kotlin/com/oksusu/susu/api/auth/model/request/OAuthRegisterRequest.kt index db41ab1a..1c8b7816 100644 --- a/api/src/main/kotlin/com/oksusu/susu/api/auth/model/request/OAuthRegisterRequest.kt +++ b/api/src/main/kotlin/com/oksusu/susu/api/auth/model/request/OAuthRegisterRequest.kt @@ -3,7 +3,7 @@ package com.oksusu.susu.api.auth.model.request import com.oksusu.susu.domain.user.domain.vo.Gender import java.time.LocalDate -class OAuthRegisterRequest( +data class OAuthRegisterRequest( /** 유저 이름 */ val name: String, /** 동의 약관 id */ @@ -14,6 +14,6 @@ class OAuthRegisterRequest( val birth: Int?, ) { fun getBirth(): LocalDate? { - return this.birth ?.let { LocalDate.of(it, 1, 1) } + return this.birth?.let { LocalDate.of(it, 1, 1) } } } diff --git a/api/src/main/kotlin/com/oksusu/susu/api/auth/model/request/OidcLoginRequest.kt b/api/src/main/kotlin/com/oksusu/susu/api/auth/model/request/OidcLoginRequest.kt new file mode 100644 index 00000000..50c220c5 --- /dev/null +++ b/api/src/main/kotlin/com/oksusu/susu/api/auth/model/request/OidcLoginRequest.kt @@ -0,0 +1,6 @@ +package com.oksusu.susu.api.auth.model.request + +data class OidcLoginRequest( + /** oauth idToken */ + val idToken: String, +) diff --git a/api/src/main/kotlin/com/oksusu/susu/api/auth/model/response/AbleRegisterResponse.kt b/api/src/main/kotlin/com/oksusu/susu/api/auth/model/response/AbleRegisterResponse.kt index e156f780..e0cc8193 100644 --- a/api/src/main/kotlin/com/oksusu/susu/api/auth/model/response/AbleRegisterResponse.kt +++ b/api/src/main/kotlin/com/oksusu/susu/api/auth/model/response/AbleRegisterResponse.kt @@ -1,6 +1,6 @@ package com.oksusu.susu.api.auth.model.response -class AbleRegisterResponse( +data class AbleRegisterResponse( /** 회원가입 가능 여부 / 가능 : 1, 불가능 : 0 */ val canRegister: Boolean, ) diff --git a/api/src/main/kotlin/com/oksusu/susu/api/auth/model/response/OAuthLoginLinkResponse.kt b/api/src/main/kotlin/com/oksusu/susu/api/auth/model/response/OAuthLoginLinkResponse.kt index 002993d3..a8bf0b9e 100644 --- a/api/src/main/kotlin/com/oksusu/susu/api/auth/model/response/OAuthLoginLinkResponse.kt +++ b/api/src/main/kotlin/com/oksusu/susu/api/auth/model/response/OAuthLoginLinkResponse.kt @@ -1,6 +1,6 @@ package com.oksusu.susu.api.auth.model.response -class OAuthLoginLinkResponse( +data class OAuthLoginLinkResponse( /** oauth 가입 url */ val link: String, ) diff --git a/api/src/main/kotlin/com/oksusu/susu/api/auth/model/response/OAuthTokenResponse.kt b/api/src/main/kotlin/com/oksusu/susu/api/auth/model/response/OAuthTokenResponse.kt index fcfbc843..4f6d8103 100644 --- a/api/src/main/kotlin/com/oksusu/susu/api/auth/model/response/OAuthTokenResponse.kt +++ b/api/src/main/kotlin/com/oksusu/susu/api/auth/model/response/OAuthTokenResponse.kt @@ -4,7 +4,7 @@ import com.oksusu.susu.client.oauth.apple.model.AppleOAuthTokenResponse import com.oksusu.susu.client.oauth.google.model.GoogleOAuthTokenResponse import com.oksusu.susu.client.oauth.kakao.model.KakaoOAuthTokenResponse -class OAuthTokenResponse( +data class OAuthTokenResponse( /** oauth access token */ val accessToken: String, /** oauth refresh token */ diff --git a/api/src/main/kotlin/com/oksusu/susu/api/auth/model/response/UserOAuthInfoResponse.kt b/api/src/main/kotlin/com/oksusu/susu/api/auth/model/response/UserOAuthInfoResponse.kt index 7339400a..86b3d385 100644 --- a/api/src/main/kotlin/com/oksusu/susu/api/auth/model/response/UserOAuthInfoResponse.kt +++ b/api/src/main/kotlin/com/oksusu/susu/api/auth/model/response/UserOAuthInfoResponse.kt @@ -3,7 +3,7 @@ package com.oksusu.susu.api.auth.model.response import com.oksusu.susu.domain.user.domain.User import com.oksusu.susu.domain.user.domain.vo.OAuthProvider -class UserOAuthInfoResponse( +data class UserOAuthInfoResponse( /** 유저 id */ val id: Long, /** 유저 oauth provider */ diff --git a/api/src/main/kotlin/com/oksusu/susu/api/auth/presentation/OAuthResource.kt b/api/src/main/kotlin/com/oksusu/susu/api/auth/presentation/OAuthResource.kt index 3648fd7a..ee39fe96 100644 --- a/api/src/main/kotlin/com/oksusu/susu/api/auth/presentation/OAuthResource.kt +++ b/api/src/main/kotlin/com/oksusu/susu/api/auth/presentation/OAuthResource.kt @@ -4,6 +4,7 @@ import com.oksusu.susu.api.auth.application.OAuthFacade import com.oksusu.susu.api.auth.model.AuthUser import com.oksusu.susu.api.auth.model.request.OAuthLoginRequest import com.oksusu.susu.api.auth.model.request.OAuthRegisterRequest +import com.oksusu.susu.api.auth.model.request.OidcLoginRequest import com.oksusu.susu.api.config.web.SwaggerTag import com.oksusu.susu.api.extension.wrapCreated import com.oksusu.susu.api.extension.wrapOk @@ -27,7 +28,7 @@ class OAuthResource( suspend fun checkRegisterValid( @PathVariable provider: OAuthProvider, @RequestParam accessToken: String, - ) = oAuthFacade.checkRegisterValid(provider, accessToken).wrapOk() + ) = oAuthFacade.checkRegisterValidWithOAuth(provider, accessToken).wrapOk() /** 회원가입을 합니다. */ @Operation(summary = "register") @@ -37,7 +38,7 @@ class OAuthResource( @PathVariable provider: OAuthProvider, @RequestBody request: OAuthRegisterRequest, @RequestParam accessToken: String, - ) = oAuthFacade.register(provider, accessToken, request, deviceContext).wrapCreated() + ) = oAuthFacade.registerWithOAuth(provider, accessToken, request, deviceContext).wrapCreated() /** 로그인을 합니다. */ @Operation(summary = "login") @@ -46,7 +47,7 @@ class OAuthResource( deviceContext: UserDeviceContext, @PathVariable provider: OAuthProvider, @RequestBody request: OAuthLoginRequest, - ) = oAuthFacade.login(provider, request, deviceContext).wrapOk() + ) = oAuthFacade.loginWithOAuth(provider, request, deviceContext).wrapOk() @Operation(summary = "연동된 소셜 로그인 정보 조회") @GetMapping("/oauth") diff --git a/api/src/main/kotlin/com/oksusu/susu/api/auth/presentation/OAuthWithdrawResource.kt b/api/src/main/kotlin/com/oksusu/susu/api/auth/presentation/OAuthWithdrawResource.kt index b4612695..310a3be3 100644 --- a/api/src/main/kotlin/com/oksusu/susu/api/auth/presentation/OAuthWithdrawResource.kt +++ b/api/src/main/kotlin/com/oksusu/susu/api/auth/presentation/OAuthWithdrawResource.kt @@ -41,7 +41,7 @@ class OAuthWithdrawResource( @RequestParam code: String, ): RedirectView { val oAuthToken = oAuthService.getOAuthWithdrawToken(OAuthProvider.KAKAO, code) - val susuToken = oAuthFacade.login( + val susuToken = oAuthFacade.loginWithOAuth( provider = OAuthProvider.KAKAO, request = OAuthLoginRequest(oAuthToken.accessToken), deviceContext = UserDeviceContextImpl.getDefault() @@ -58,7 +58,7 @@ class OAuthWithdrawResource( @RequestParam code: String, ): RedirectView { val googleAccessToken = oAuthService.getOAuthWithdrawToken(OAuthProvider.GOOGLE, code).accessToken - val susuToken = oAuthFacade.login( + val susuToken = oAuthFacade.loginWithOAuth( provider = OAuthProvider.GOOGLE, request = OAuthLoginRequest(googleAccessToken), deviceContext = UserDeviceContextImpl.getDefault() diff --git a/api/src/main/kotlin/com/oksusu/susu/api/auth/presentation/OidcResource.kt b/api/src/main/kotlin/com/oksusu/susu/api/auth/presentation/OidcResource.kt new file mode 100644 index 00000000..c01c7d58 --- /dev/null +++ b/api/src/main/kotlin/com/oksusu/susu/api/auth/presentation/OidcResource.kt @@ -0,0 +1,51 @@ +package com.oksusu.susu.api.auth.presentation + +import com.oksusu.susu.api.auth.application.OAuthFacade +import com.oksusu.susu.api.auth.model.AuthUser +import com.oksusu.susu.api.auth.model.request.OAuthLoginRequest +import com.oksusu.susu.api.auth.model.request.OAuthRegisterRequest +import com.oksusu.susu.api.auth.model.request.OidcLoginRequest +import com.oksusu.susu.api.config.web.SwaggerTag +import com.oksusu.susu.api.extension.wrapCreated +import com.oksusu.susu.api.extension.wrapOk +import com.oksusu.susu.api.user.model.UserDeviceContext +import com.oksusu.susu.domain.user.domain.vo.OAuthProvider +import io.swagger.v3.oas.annotations.Operation +import io.swagger.v3.oas.annotations.tags.Tag +import org.springframework.http.MediaType +import org.springframework.web.bind.annotation.* + +@Tag(name = SwaggerTag.OAUTH_OIDC_SWAGGER_TAG, description = "OAuth Oidc API") +@RestController +@RequestMapping(value = ["/api/v1/oauth/oidc"], produces = [MediaType.APPLICATION_JSON_VALUE]) +class OidcResource( + private val oAuthFacade: OAuthFacade, +) { + + /** 가입된 유저인지 체크합니다. (현재 Google만 지원) */ + @Operation(summary = "register valid check") + @GetMapping("/{provider}/sign-up/valid") + suspend fun checkRegisterValid( + @PathVariable provider: OAuthProvider, + @RequestParam idToken: String, + ) = oAuthFacade.checkRegisterValidWithOidc(provider, idToken).wrapOk() + + /** 회원가입을 합니다. (현재 Google만 지원) */ + @Operation(summary = "register") + @PostMapping("/{provider}/sign-up") + suspend fun register( + deviceContext: UserDeviceContext, + @PathVariable provider: OAuthProvider, + @RequestBody request: OAuthRegisterRequest, + @RequestParam idToken: String, + ) = oAuthFacade.registerWithOidc(provider, idToken, request, deviceContext).wrapCreated() + + /** OIDC 로그인을 합니다. (현재 Google만 지원) */ + @Operation(summary = "login oidc") + @PostMapping("/{provider}/login") + suspend fun loginWithOidc( + deviceContext: UserDeviceContext, + @PathVariable provider: OAuthProvider, + @RequestBody request: OidcLoginRequest, + ) = oAuthFacade.loginWithOidc(provider, request, deviceContext).wrapOk() +} diff --git a/api/src/main/kotlin/com/oksusu/susu/api/config/web/SpringDocConfig.kt b/api/src/main/kotlin/com/oksusu/susu/api/config/web/SpringDocConfig.kt index 39e1eb5f..a9431f35 100644 --- a/api/src/main/kotlin/com/oksusu/susu/api/config/web/SpringDocConfig.kt +++ b/api/src/main/kotlin/com/oksusu/susu/api/config/web/SpringDocConfig.kt @@ -74,6 +74,7 @@ object SwaggerTag { const val STATISTIC_SWAGGER_TAG = "Statistic API" const val AUTH_SWAGGER_TAG = "Auth API" const val OAUTH_SWAGGER_TAG = "OAuth API" + const val OAUTH_OIDC_SWAGGER_TAG = "OAuth Oidc API" const val CATEGORY_SWAGGER_TAG = "Category API" const val DEV_SWAGGER_TAG = "DEV API" const val DEV_OAUTH_SWAGGER_TAG = "DEV OAuth API" diff --git a/api/src/main/kotlin/com/oksusu/susu/api/count/model/CountModel.kt b/api/src/main/kotlin/com/oksusu/susu/api/count/model/CountModel.kt index e6893bfa..3182afeb 100644 --- a/api/src/main/kotlin/com/oksusu/susu/api/count/model/CountModel.kt +++ b/api/src/main/kotlin/com/oksusu/susu/api/count/model/CountModel.kt @@ -4,7 +4,7 @@ import com.oksusu.susu.domain.count.domain.vo.CountTargetType import com.oksusu.susu.domain.count.domain.vo.CountType /** 카운트 모델 */ -class CountModel( +data class CountModel( /** 카운트 id */ val id: Long, /** 카운트 타켓 id */ diff --git a/api/src/main/kotlin/com/oksusu/susu/api/excel/model/AllEnvelopeSheetDataDto.kt b/api/src/main/kotlin/com/oksusu/susu/api/excel/model/AllEnvelopeSheetDataDto.kt index 5a5ae49b..b17d5dc4 100644 --- a/api/src/main/kotlin/com/oksusu/susu/api/excel/model/AllEnvelopeSheetDataDto.kt +++ b/api/src/main/kotlin/com/oksusu/susu/api/excel/model/AllEnvelopeSheetDataDto.kt @@ -6,7 +6,7 @@ import com.oksusu.susu.common.extension.format import com.oksusu.susu.common.extension.toOX import com.oksusu.susu.domain.envelope.infrastructure.model.EnvelopeDetailAndLedgerModel -class AllEnvelopeSheetDataDto( +data class AllEnvelopeSheetDataDto( val date: String, val categoryName: String, val relationship: String, diff --git a/api/src/main/kotlin/com/oksusu/susu/api/metadata/model/ApplicationMetadataModel.kt b/api/src/main/kotlin/com/oksusu/susu/api/metadata/model/ApplicationMetadataModel.kt index fa0af188..c49300be 100644 --- a/api/src/main/kotlin/com/oksusu/susu/api/metadata/model/ApplicationMetadataModel.kt +++ b/api/src/main/kotlin/com/oksusu/susu/api/metadata/model/ApplicationMetadataModel.kt @@ -3,7 +3,7 @@ package com.oksusu.susu.api.metadata.model import java.time.LocalDateTime /** 어플리케이션 설정 정보 */ -class ApplicationMetadataModel( +data class ApplicationMetadataModel( val id: Long, /** 최신 어플리케이션 버전 */ val applicationVersion: String, diff --git a/api/src/main/kotlin/com/oksusu/susu/api/metadata/model/response/ApplicationVersionMetadataResponse.kt b/api/src/main/kotlin/com/oksusu/susu/api/metadata/model/response/ApplicationVersionMetadataResponse.kt index 5e255766..d45cfdf5 100644 --- a/api/src/main/kotlin/com/oksusu/susu/api/metadata/model/response/ApplicationVersionMetadataResponse.kt +++ b/api/src/main/kotlin/com/oksusu/susu/api/metadata/model/response/ApplicationVersionMetadataResponse.kt @@ -2,9 +2,9 @@ package com.oksusu.susu.api.metadata.model.response import java.time.LocalDateTime -class ApplicationVersionMetadataResponse( +data class ApplicationVersionMetadataResponse( /** 최신 어플리케이션 버전 */ - var applicationVersion: String, + val applicationVersion: String, /** 강제 업데이트 날짜 */ - var forcedUpdateDate: LocalDateTime, + val forcedUpdateDate: LocalDateTime, ) diff --git a/api/src/main/kotlin/com/oksusu/susu/api/post/model/response/OnboardingVoteResponse.kt b/api/src/main/kotlin/com/oksusu/susu/api/post/model/response/OnboardingVoteResponse.kt index dd4f2ed0..965ae9b3 100644 --- a/api/src/main/kotlin/com/oksusu/susu/api/post/model/response/OnboardingVoteResponse.kt +++ b/api/src/main/kotlin/com/oksusu/susu/api/post/model/response/OnboardingVoteResponse.kt @@ -2,7 +2,7 @@ package com.oksusu.susu.api.post.model.response import com.oksusu.susu.api.post.model.OnboardingVoteOptionCountModel -class OnboardingVoteResponse( +data class OnboardingVoteResponse( /** 투표 옵션 */ val options: List, ) diff --git a/api/src/main/kotlin/com/oksusu/susu/api/post/model/response/VoteAndOptionsWithCountResponse.kt b/api/src/main/kotlin/com/oksusu/susu/api/post/model/response/VoteAndOptionsWithCountResponse.kt index dc5a8f65..b983c843 100644 --- a/api/src/main/kotlin/com/oksusu/susu/api/post/model/response/VoteAndOptionsWithCountResponse.kt +++ b/api/src/main/kotlin/com/oksusu/susu/api/post/model/response/VoteAndOptionsWithCountResponse.kt @@ -6,7 +6,7 @@ import com.oksusu.susu.common.extension.equalsFromYearToSec import com.oksusu.susu.domain.post.domain.Post import java.time.LocalDateTime -class VoteAndOptionsWithCountResponse( +data class VoteAndOptionsWithCountResponse( /** 투표 id */ val id: Long, /** 투표 생성자 id */ diff --git a/api/src/main/kotlin/com/oksusu/susu/api/slack/application/SlackBlockHelper.kt b/api/src/main/kotlin/com/oksusu/susu/api/slack/application/SlackBlockHelper.kt index 43b9e24e..6bd6b783 100644 --- a/api/src/main/kotlin/com/oksusu/susu/api/slack/application/SlackBlockHelper.kt +++ b/api/src/main/kotlin/com/oksusu/susu/api/slack/application/SlackBlockHelper.kt @@ -94,6 +94,7 @@ class SlackBlockHelper { private fun getRequestParam(request: ServerHttpRequest): String { return request.queryParams.map { param -> + @Suppress("IMPLICIT_CAST_TO_ANY") val value = when (param.value.size == 1) { true -> param.value.firstOrNull() false -> param.value diff --git a/api/src/main/kotlin/com/oksusu/susu/api/slack/model/ErrorWebhookDataModel.kt b/api/src/main/kotlin/com/oksusu/susu/api/slack/model/ErrorWebhookDataModel.kt index d62c9bd0..8e67c929 100644 --- a/api/src/main/kotlin/com/oksusu/susu/api/slack/model/ErrorWebhookDataModel.kt +++ b/api/src/main/kotlin/com/oksusu/susu/api/slack/model/ErrorWebhookDataModel.kt @@ -1,9 +1,8 @@ package com.oksusu.susu.api.slack.model import org.springframework.http.server.reactive.ServerHttpRequest -import java.lang.Exception -class ErrorWebhookDataModel( +data class ErrorWebhookDataModel( val request: ServerHttpRequest, val exception: Exception, ) diff --git a/api/src/main/kotlin/com/oksusu/susu/api/statistic/model/SusuEnvelopeStatisticModel.kt b/api/src/main/kotlin/com/oksusu/susu/api/statistic/model/SusuEnvelopeStatisticModel.kt index a6a168d1..75d5bd9a 100644 --- a/api/src/main/kotlin/com/oksusu/susu/api/statistic/model/SusuEnvelopeStatisticModel.kt +++ b/api/src/main/kotlin/com/oksusu/susu/api/statistic/model/SusuEnvelopeStatisticModel.kt @@ -2,7 +2,7 @@ package com.oksusu.susu.api.statistic.model import com.oksusu.susu.common.model.TitleValueModel -class SusuEnvelopeStatisticModel( +data class SusuEnvelopeStatisticModel( /** 최근 사용 금액 */ val recentSpent: List>?, /** 경조사비를 가장 많이 쓴 달 */ diff --git a/api/src/main/kotlin/com/oksusu/susu/api/statistic/model/response/UserEnvelopeStatisticResponse.kt b/api/src/main/kotlin/com/oksusu/susu/api/statistic/model/response/UserEnvelopeStatisticResponse.kt index 48de5242..7ce548e5 100644 --- a/api/src/main/kotlin/com/oksusu/susu/api/statistic/model/response/UserEnvelopeStatisticResponse.kt +++ b/api/src/main/kotlin/com/oksusu/susu/api/statistic/model/response/UserEnvelopeStatisticResponse.kt @@ -3,7 +3,7 @@ package com.oksusu.susu.api.statistic.model.response import com.oksusu.susu.cache.statistic.domain.UserEnvelopeStatistic import com.oksusu.susu.common.model.TitleValueModel -class UserEnvelopeStatisticResponse( +data class UserEnvelopeStatisticResponse( /** 최근 사용 금액 */ val recentSpent: List>?, /** 경조사비를 가장 많이 쓴 달 */ diff --git a/api/src/main/kotlin/com/oksusu/susu/api/user/model/BlockModel.kt b/api/src/main/kotlin/com/oksusu/susu/api/user/model/BlockModel.kt index ebf95fc2..c1aadf80 100644 --- a/api/src/main/kotlin/com/oksusu/susu/api/user/model/BlockModel.kt +++ b/api/src/main/kotlin/com/oksusu/susu/api/user/model/BlockModel.kt @@ -3,7 +3,7 @@ package com.oksusu.susu.api.user.model import com.oksusu.susu.domain.user.domain.vo.UserBlockTargetType /** 차단 모델 */ -class BlockModel( +data class BlockModel( /** 차단 id */ val id: Long, /** 차단하는 유저 id */ diff --git a/api/src/main/kotlin/com/oksusu/susu/api/user/model/UserAndPostBlockIdModel.kt b/api/src/main/kotlin/com/oksusu/susu/api/user/model/UserAndPostBlockIdModel.kt index 92141eea..650b1e61 100644 --- a/api/src/main/kotlin/com/oksusu/susu/api/user/model/UserAndPostBlockIdModel.kt +++ b/api/src/main/kotlin/com/oksusu/susu/api/user/model/UserAndPostBlockIdModel.kt @@ -1,7 +1,7 @@ package com.oksusu.susu.api.user.model /** 차단 유저, post id 제공하는 모델 */ -class UserAndPostBlockIdModel( +data class UserAndPostBlockIdModel( /** 유저 차단 id */ val userBlockIds: Set, /** 게시글 차단 id */ diff --git a/api/src/main/kotlin/com/oksusu/susu/api/user/model/UserDeviceContext.kt b/api/src/main/kotlin/com/oksusu/susu/api/user/model/UserDeviceContext.kt index 30570563..996637d2 100644 --- a/api/src/main/kotlin/com/oksusu/susu/api/user/model/UserDeviceContext.kt +++ b/api/src/main/kotlin/com/oksusu/susu/api/user/model/UserDeviceContext.kt @@ -35,7 +35,7 @@ interface UserDeviceContext { val simState: String? } -class UserDeviceContextImpl( +data class UserDeviceContextImpl( override val applicationVersion: String?, override val deviceId: String?, override val deviceSoftwareVersion: String?, diff --git a/api/src/main/kotlin/com/oksusu/susu/api/user/model/UserStatusTypeModel.kt b/api/src/main/kotlin/com/oksusu/susu/api/user/model/UserStatusTypeModel.kt index 7648bda9..744aa24a 100644 --- a/api/src/main/kotlin/com/oksusu/susu/api/user/model/UserStatusTypeModel.kt +++ b/api/src/main/kotlin/com/oksusu/susu/api/user/model/UserStatusTypeModel.kt @@ -4,7 +4,7 @@ import com.oksusu.susu.domain.user.domain.UserStatusType import com.oksusu.susu.domain.user.domain.vo.UserStatusTypeInfo /** 유저 상태 정보 타입 */ -class UserStatusTypeModel( +data class UserStatusTypeModel( val id: Long = -1, /** 상태 정보 타입 정보 */ val statusTypeInfo: UserStatusTypeInfo, diff --git a/api/src/main/kotlin/com/oksusu/susu/api/user/model/request/CreateBlockRequest.kt b/api/src/main/kotlin/com/oksusu/susu/api/user/model/request/CreateBlockRequest.kt index ad0dddd7..4547ccc1 100644 --- a/api/src/main/kotlin/com/oksusu/susu/api/user/model/request/CreateBlockRequest.kt +++ b/api/src/main/kotlin/com/oksusu/susu/api/user/model/request/CreateBlockRequest.kt @@ -2,7 +2,7 @@ package com.oksusu.susu.api.user.model.request import com.oksusu.susu.domain.user.domain.vo.UserBlockTargetType -class CreateBlockRequest( +data class CreateBlockRequest( /** 차단 타겟 id */ val targetId: Long, /** 차단 타겟 타입 */ diff --git a/api/src/main/kotlin/com/oksusu/susu/api/user/model/request/DeleteBlockRequest.kt b/api/src/main/kotlin/com/oksusu/susu/api/user/model/request/DeleteBlockRequest.kt index 5234197d..041a16ed 100644 --- a/api/src/main/kotlin/com/oksusu/susu/api/user/model/request/DeleteBlockRequest.kt +++ b/api/src/main/kotlin/com/oksusu/susu/api/user/model/request/DeleteBlockRequest.kt @@ -2,7 +2,7 @@ package com.oksusu.susu.api.user.model.request import com.oksusu.susu.domain.user.domain.vo.UserBlockTargetType -class DeleteBlockRequest( +data class DeleteBlockRequest( /** 차단 타겟 id */ val targetId: Long, /** 차단 타겟 타입 */ diff --git a/api/src/main/kotlin/com/oksusu/susu/api/user/model/response/UserInfoResponse.kt b/api/src/main/kotlin/com/oksusu/susu/api/user/model/response/UserInfoResponse.kt index 4c9cee30..9d662fed 100644 --- a/api/src/main/kotlin/com/oksusu/susu/api/user/model/response/UserInfoResponse.kt +++ b/api/src/main/kotlin/com/oksusu/susu/api/user/model/response/UserInfoResponse.kt @@ -3,7 +3,7 @@ package com.oksusu.susu.api.user.model.response import com.oksusu.susu.domain.user.domain.User import com.oksusu.susu.domain.user.domain.vo.Gender -class UserInfoResponse( +data class UserInfoResponse( /** 유저 id */ val id: Long, /** 이름 */ diff --git a/cache/src/main/kotlin/com/oksusu/susu/cache/auth/domain/RefreshToken.kt b/cache/src/main/kotlin/com/oksusu/susu/cache/auth/domain/RefreshToken.kt index dd2701b5..aefa2a96 100644 --- a/cache/src/main/kotlin/com/oksusu/susu/cache/auth/domain/RefreshToken.kt +++ b/cache/src/main/kotlin/com/oksusu/susu/cache/auth/domain/RefreshToken.kt @@ -1,7 +1,7 @@ package com.oksusu.susu.cache.auth.domain /** refresh token */ -class RefreshToken( +data class RefreshToken( /** 리프레시 토큰 해당 유저 */ val uid: Long, /** 리프레시 토큰 */ diff --git a/cache/src/main/kotlin/com/oksusu/susu/cache/key/Cache.kt b/cache/src/main/kotlin/com/oksusu/susu/cache/key/Cache.kt index 59f9d3ed..2c15f64c 100644 --- a/cache/src/main/kotlin/com/oksusu/susu/cache/key/Cache.kt +++ b/cache/src/main/kotlin/com/oksusu/susu/cache/key/Cache.kt @@ -4,14 +4,11 @@ import com.fasterxml.jackson.core.type.TypeReference import com.oksusu.susu.cache.model.OidcPublicKeysCacheModel import com.oksusu.susu.cache.model.SusuEnvelopeStatisticCacheModel import com.oksusu.susu.cache.model.UserEnvelopeStatisticCacheModel -import com.oksusu.susu.common.consts.APPLE_OIDC_PUBLIC_KEY_KEY -import com.oksusu.susu.common.consts.SUSU_ENVELOPE_STATISTIC_KEY -import com.oksusu.susu.common.consts.SUSU_STATISTIC_TTL -import com.oksusu.susu.common.consts.USER_STATISTIC_TTL +import com.oksusu.susu.common.consts.* import com.oksusu.susu.common.util.toTypeReference import java.time.Duration -class Cache( +data class Cache( val key: String, val type: TypeReference, val duration: Duration, @@ -56,7 +53,15 @@ class Cache( return Cache( key = APPLE_OIDC_PUBLIC_KEY_KEY, type = toTypeReference(), - duration = Duration.ofDays(7) + duration = Duration.ofSeconds(APPLE_OIDC_PUBLIC_KEY_TTL) + ) + } + + fun getGoogleOidcPublicKeyCache(): Cache { + return Cache( + key = GOOGLE_OIDC_PUBLIC_KEY_KEY, + type = toTypeReference(), + duration = Duration.ofDays(GOOGLE_OIDC_PUBLIC_KEY_TTL) ) } } diff --git a/cache/src/main/kotlin/com/oksusu/susu/cache/key/ZSetCache.kt b/cache/src/main/kotlin/com/oksusu/susu/cache/key/ZSetCache.kt index 8dfb8018..b50c6e6c 100644 --- a/cache/src/main/kotlin/com/oksusu/susu/cache/key/ZSetCache.kt +++ b/cache/src/main/kotlin/com/oksusu/susu/cache/key/ZSetCache.kt @@ -5,7 +5,7 @@ import com.oksusu.susu.common.consts.VOTE_OPTION_SUMMARY_KEY import com.oksusu.susu.common.consts.VOTE_SUMMARY_KEY import com.oksusu.susu.common.util.toTypeReference -class ZSetCache( +data class ZSetCache( val key: String, val type: TypeReference, ) { diff --git a/cache/src/main/kotlin/com/oksusu/susu/cache/model/OidcPublicKeysCacheModel.kt b/cache/src/main/kotlin/com/oksusu/susu/cache/model/OidcPublicKeysCacheModel.kt index bd0982dc..45c98b67 100644 --- a/cache/src/main/kotlin/com/oksusu/susu/cache/model/OidcPublicKeysCacheModel.kt +++ b/cache/src/main/kotlin/com/oksusu/susu/cache/model/OidcPublicKeysCacheModel.kt @@ -2,6 +2,6 @@ package com.oksusu.susu.cache.model import com.oksusu.susu.cache.model.vo.OidcPublicKeyCacheModel -class OidcPublicKeysCacheModel( +data class OidcPublicKeysCacheModel( val keys: List, ) diff --git a/cache/src/main/kotlin/com/oksusu/susu/cache/model/SusuEnvelopeStatisticCacheModel.kt b/cache/src/main/kotlin/com/oksusu/susu/cache/model/SusuEnvelopeStatisticCacheModel.kt index 84c1e4a4..033b48f5 100644 --- a/cache/src/main/kotlin/com/oksusu/susu/cache/model/SusuEnvelopeStatisticCacheModel.kt +++ b/cache/src/main/kotlin/com/oksusu/susu/cache/model/SusuEnvelopeStatisticCacheModel.kt @@ -2,7 +2,7 @@ package com.oksusu.susu.cache.model import com.oksusu.susu.common.model.TitleValueModel -class SusuEnvelopeStatisticCacheModel( +data class SusuEnvelopeStatisticCacheModel( /** 최근 사용 금액 */ val recentSpent: List>?, /** 경조사비를 가장 많이 쓴 달 */ diff --git a/cache/src/main/kotlin/com/oksusu/susu/cache/model/UserEnvelopeStatisticCacheModel.kt b/cache/src/main/kotlin/com/oksusu/susu/cache/model/UserEnvelopeStatisticCacheModel.kt index 7ece5dfb..cba9df28 100644 --- a/cache/src/main/kotlin/com/oksusu/susu/cache/model/UserEnvelopeStatisticCacheModel.kt +++ b/cache/src/main/kotlin/com/oksusu/susu/cache/model/UserEnvelopeStatisticCacheModel.kt @@ -2,7 +2,7 @@ package com.oksusu.susu.cache.model import com.oksusu.susu.common.model.TitleValueModel -class UserEnvelopeStatisticCacheModel( +data class UserEnvelopeStatisticCacheModel( /** 최근 사용 금액 */ val recentSpent: List>?, /** 경조사비를 가장 많이 쓴 달 */ diff --git a/cache/src/main/kotlin/com/oksusu/susu/cache/model/ZSetModel.kt b/cache/src/main/kotlin/com/oksusu/susu/cache/model/ZSetModel.kt index 33c8f862..353cc09d 100644 --- a/cache/src/main/kotlin/com/oksusu/susu/cache/model/ZSetModel.kt +++ b/cache/src/main/kotlin/com/oksusu/susu/cache/model/ZSetModel.kt @@ -1,6 +1,6 @@ package com.oksusu.susu.cache.model -class ZSetModel( +data class ZSetModel( val key: String?, val value: VALUE_TYPE?, val score: Double?, diff --git a/cache/src/main/kotlin/com/oksusu/susu/cache/model/vo/OidcPublicKeyCacheModel.kt b/cache/src/main/kotlin/com/oksusu/susu/cache/model/vo/OidcPublicKeyCacheModel.kt index f0e5ee12..842ec884 100644 --- a/cache/src/main/kotlin/com/oksusu/susu/cache/model/vo/OidcPublicKeyCacheModel.kt +++ b/cache/src/main/kotlin/com/oksusu/susu/cache/model/vo/OidcPublicKeyCacheModel.kt @@ -1,6 +1,6 @@ package com.oksusu.susu.cache.model.vo -class OidcPublicKeyCacheModel( +data class OidcPublicKeyCacheModel( val kid: String, val alg: String, val use: String, diff --git a/client/src/main/kotlin/com/oksusu/susu/client/config/OAuthUrlConfig.kt b/client/src/main/kotlin/com/oksusu/susu/client/config/OAuthUrlConfig.kt index 40507557..a3ec61c6 100644 --- a/client/src/main/kotlin/com/oksusu/susu/client/config/OAuthUrlConfig.kt +++ b/client/src/main/kotlin/com/oksusu/susu/client/config/OAuthUrlConfig.kt @@ -63,6 +63,7 @@ class OAuthUrlConfig( val accountGoogleUrl: String, val oauth2GoogleApiUrl: String, val googleApiUrl: String, + val oidcKeyUrl: String, val redirectUrl: String, ) } diff --git a/client/src/main/kotlin/com/oksusu/susu/client/oauth/google/GoogleClient.kt b/client/src/main/kotlin/com/oksusu/susu/client/oauth/google/GoogleClient.kt index 1eeb3483..25df63e4 100644 --- a/client/src/main/kotlin/com/oksusu/susu/client/oauth/google/GoogleClient.kt +++ b/client/src/main/kotlin/com/oksusu/susu/client/oauth/google/GoogleClient.kt @@ -2,6 +2,7 @@ package com.oksusu.susu.client.oauth.google import com.oksusu.susu.client.oauth.google.model.GoogleOAuthTokenResponse import com.oksusu.susu.client.oauth.google.model.GoogleOAuthUserInfoResponse +import com.oksusu.susu.client.oauth.oidc.model.OidcPublicKeysResponse interface GoogleClient { suspend fun getToken( @@ -13,5 +14,7 @@ interface GoogleClient { suspend fun getUserInfo(accessToken: String): GoogleOAuthUserInfoResponse + suspend fun getOidcPublicKeys(): OidcPublicKeysResponse + suspend fun withdraw(accessToken: String): String? } diff --git a/client/src/main/kotlin/com/oksusu/susu/client/oauth/google/SuspendableGoogleClient.kt b/client/src/main/kotlin/com/oksusu/susu/client/oauth/google/SuspendableGoogleClient.kt index 3de3c493..63b538ca 100644 --- a/client/src/main/kotlin/com/oksusu/susu/client/oauth/google/SuspendableGoogleClient.kt +++ b/client/src/main/kotlin/com/oksusu/susu/client/oauth/google/SuspendableGoogleClient.kt @@ -3,6 +3,7 @@ package com.oksusu.susu.client.oauth.google import com.oksusu.susu.client.config.OAuthUrlConfig import com.oksusu.susu.client.oauth.google.model.GoogleOAuthTokenResponse import com.oksusu.susu.client.oauth.google.model.GoogleOAuthUserInfoResponse +import com.oksusu.susu.client.oauth.oidc.model.OidcPublicKeysResponse import io.github.oshai.kotlinlogging.KotlinLogging import kotlinx.coroutines.reactor.awaitSingle import org.springframework.http.MediaType @@ -46,6 +47,16 @@ class SuspendableGoogleClient( .awaitSingle() } + override suspend fun getOidcPublicKeys(): OidcPublicKeysResponse { + val url = googleOAuthUrlConfig.googleApiUrl + googleOAuthUrlConfig.oidcKeyUrl + + return webClient.get() + .uri(url) + .retrieve() + .bodyToMono(OidcPublicKeysResponse::class.java) + .awaitSingle() + } + override suspend fun withdraw(accessToken: String): String? { val url = googleOAuthUrlConfig.oauth2GoogleApiUrl + String.format( googleOAuthUrlConfig.revokeUrl, diff --git a/client/src/main/kotlin/com/oksusu/susu/client/oauth/google/model/GoogleOAuthTokenResponse.kt b/client/src/main/kotlin/com/oksusu/susu/client/oauth/google/model/GoogleOAuthTokenResponse.kt index ec492bcc..cf6e8414 100644 --- a/client/src/main/kotlin/com/oksusu/susu/client/oauth/google/model/GoogleOAuthTokenResponse.kt +++ b/client/src/main/kotlin/com/oksusu/susu/client/oauth/google/model/GoogleOAuthTokenResponse.kt @@ -25,4 +25,8 @@ data class GoogleOAuthTokenResponse( * Google accessToken type */ val tokenType: String, + /** + * Google idToken + */ + val idToken: String, ) diff --git a/client/src/main/kotlin/com/oksusu/susu/client/oauth/google/model/GoogleOAuthUserInfoResponse.kt b/client/src/main/kotlin/com/oksusu/susu/client/oauth/google/model/GoogleOAuthUserInfoResponse.kt index cce248da..fdfa5b45 100644 --- a/client/src/main/kotlin/com/oksusu/susu/client/oauth/google/model/GoogleOAuthUserInfoResponse.kt +++ b/client/src/main/kotlin/com/oksusu/susu/client/oauth/google/model/GoogleOAuthUserInfoResponse.kt @@ -1,6 +1,6 @@ package com.oksusu.susu.client.oauth.google.model -class GoogleOAuthUserInfoResponse( +data class GoogleOAuthUserInfoResponse( /** 구글 유저 id */ val id: String, ) diff --git a/client/src/main/kotlin/com/oksusu/susu/client/oauth/kakao/model/KakaoOAuthUserInfoResponse.kt b/client/src/main/kotlin/com/oksusu/susu/client/oauth/kakao/model/KakaoOAuthUserInfoResponse.kt index 9a853633..433aba56 100644 --- a/client/src/main/kotlin/com/oksusu/susu/client/oauth/kakao/model/KakaoOAuthUserInfoResponse.kt +++ b/client/src/main/kotlin/com/oksusu/susu/client/oauth/kakao/model/KakaoOAuthUserInfoResponse.kt @@ -1,6 +1,6 @@ package com.oksusu.susu.client.oauth.kakao.model -class KakaoOAuthUserInfoResponse( +data class KakaoOAuthUserInfoResponse( /** 카카오 유저 id */ val id: String, ) diff --git a/client/src/main/kotlin/com/oksusu/susu/client/oauth/kakao/model/KakaoOAuthWithdrawRequest.kt b/client/src/main/kotlin/com/oksusu/susu/client/oauth/kakao/model/KakaoOAuthWithdrawRequest.kt index 97e7ef31..2533ba64 100644 --- a/client/src/main/kotlin/com/oksusu/susu/client/oauth/kakao/model/KakaoOAuthWithdrawRequest.kt +++ b/client/src/main/kotlin/com/oksusu/susu/client/oauth/kakao/model/KakaoOAuthWithdrawRequest.kt @@ -4,7 +4,7 @@ import com.fasterxml.jackson.databind.PropertyNamingStrategies import com.fasterxml.jackson.databind.annotation.JsonNaming @JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy::class) -class KakaoOAuthWithdrawRequest( +data class KakaoOAuthWithdrawRequest( /** 카카오 회원 탈퇴 타입 */ val targetIdType: String = "user_id", /** 카카오 회원 탈퇴 id */ diff --git a/client/src/main/kotlin/com/oksusu/susu/client/oauth/kakao/model/KakaoOAuthWithdrawResponse.kt b/client/src/main/kotlin/com/oksusu/susu/client/oauth/kakao/model/KakaoOAuthWithdrawResponse.kt index 86f6ed50..fd73ab99 100644 --- a/client/src/main/kotlin/com/oksusu/susu/client/oauth/kakao/model/KakaoOAuthWithdrawResponse.kt +++ b/client/src/main/kotlin/com/oksusu/susu/client/oauth/kakao/model/KakaoOAuthWithdrawResponse.kt @@ -4,7 +4,7 @@ import com.fasterxml.jackson.databind.PropertyNamingStrategies import com.fasterxml.jackson.databind.annotation.JsonNaming @JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy::class) -class KakaoOAuthWithdrawResponse( +data class KakaoOAuthWithdrawResponse( /** 카카오 회원 탈퇴 유저 id */ val id: String, ) diff --git a/client/src/main/kotlin/com/oksusu/susu/client/oauth/oidc/model/OidcPublicKeyModel.kt b/client/src/main/kotlin/com/oksusu/susu/client/oauth/oidc/model/OidcPublicKeyModel.kt index cc62a841..a3bddd7d 100644 --- a/client/src/main/kotlin/com/oksusu/susu/client/oauth/oidc/model/OidcPublicKeyModel.kt +++ b/client/src/main/kotlin/com/oksusu/susu/client/oauth/oidc/model/OidcPublicKeyModel.kt @@ -1,6 +1,6 @@ package com.oksusu.susu.client.oauth.oidc.model -class OidcPublicKeyModel( +data class OidcPublicKeyModel( val kid: String, val alg: String, val use: String, diff --git a/client/src/main/kotlin/com/oksusu/susu/client/oauth/oidc/model/OidcPublicKeysResponse.kt b/client/src/main/kotlin/com/oksusu/susu/client/oauth/oidc/model/OidcPublicKeysResponse.kt index 8a651a29..5f81fe95 100644 --- a/client/src/main/kotlin/com/oksusu/susu/client/oauth/oidc/model/OidcPublicKeysResponse.kt +++ b/client/src/main/kotlin/com/oksusu/susu/client/oauth/oidc/model/OidcPublicKeysResponse.kt @@ -1,5 +1,5 @@ package com.oksusu.susu.client.oauth.oidc.model -class OidcPublicKeysResponse( +data class OidcPublicKeysResponse( val keys: List, ) diff --git a/client/src/main/resources/application-client.yml b/client/src/main/resources/application-client.yml index d7927da1..2e7532e8 100644 --- a/client/src/main/resources/application-client.yml +++ b/client/src/main/resources/application-client.yml @@ -41,6 +41,7 @@ oauth-url: account-google-url: ${GOOGLE_ACCOUNT_GOOGLE_URL} oauth2-google-api-url: ${GOOGLE_OAUTH2_GOOGLE_API_URL} google-api-url: ${GOOGLE_GOOGLE_API_URL} + oidc-key-url: ${GOOGLE_OIDC_KEY_URL} redirect-url: ${GOOGLE_REDIRECT_URL} --- diff --git a/common/src/main/kotlin/com/oksusu/susu/common/consts/SusuConsts.kt b/common/src/main/kotlin/com/oksusu/susu/common/consts/SusuConsts.kt index b50f6c11..99951bca 100644 --- a/common/src/main/kotlin/com/oksusu/susu/common/consts/SusuConsts.kt +++ b/common/src/main/kotlin/com/oksusu/susu/common/consts/SusuConsts.kt @@ -18,6 +18,8 @@ const val VOTE_SUMMARY_KEY = "vote_summary" const val FAIL_TO_VALIDATE_MESSAGE = "fail to validate" const val APPLE_OIDC_PUBLIC_KEY_KEY = "apple_oidc_public_key" -const val APPLE_OIDC_PUBLIC_KEY_TTL = 7 +const val GOOGLE_OIDC_PUBLIC_KEY_KEY = "google_oidc_public_key" +const val APPLE_OIDC_PUBLIC_KEY_TTL = 60 * 60 * 24 * 7L +const val GOOGLE_OIDC_PUBLIC_KEY_TTL = 60 * 5L const val KID = "kid" diff --git a/domain/src/main/kotlin/com/oksusu/susu/domain/envelope/infrastructure/model/EnvelopeAndFriendModel.kt b/domain/src/main/kotlin/com/oksusu/susu/domain/envelope/infrastructure/model/EnvelopeAndFriendModel.kt index 90606fcc..d4afa9c2 100644 --- a/domain/src/main/kotlin/com/oksusu/susu/domain/envelope/infrastructure/model/EnvelopeAndFriendModel.kt +++ b/domain/src/main/kotlin/com/oksusu/susu/domain/envelope/infrastructure/model/EnvelopeAndFriendModel.kt @@ -4,7 +4,7 @@ import com.oksusu.susu.domain.envelope.domain.Envelope import com.oksusu.susu.domain.friend.domain.Friend import com.querydsl.core.annotations.QueryProjection -class EnvelopeAndFriendModel @QueryProjection constructor( +data class EnvelopeAndFriendModel @QueryProjection constructor( val envelope: Envelope, val friend: Friend, ) diff --git a/domain/src/main/kotlin/com/oksusu/susu/domain/envelope/infrastructure/model/EnvelopeAndRelationshipModel.kt b/domain/src/main/kotlin/com/oksusu/susu/domain/envelope/infrastructure/model/EnvelopeAndRelationshipModel.kt index 10d4c09c..bb0ee312 100644 --- a/domain/src/main/kotlin/com/oksusu/susu/domain/envelope/infrastructure/model/EnvelopeAndRelationshipModel.kt +++ b/domain/src/main/kotlin/com/oksusu/susu/domain/envelope/infrastructure/model/EnvelopeAndRelationshipModel.kt @@ -4,7 +4,7 @@ import com.oksusu.susu.domain.envelope.domain.Envelope import com.oksusu.susu.domain.friend.domain.Relationship import com.querydsl.core.annotations.QueryProjection -class EnvelopeAndRelationshipModel @QueryProjection constructor( +data class EnvelopeAndRelationshipModel @QueryProjection constructor( val envelope: Envelope, val relationship: Relationship, ) diff --git a/domain/src/main/kotlin/com/oksusu/susu/domain/post/infrastructure/repository/model/GetVoteSpec.kt b/domain/src/main/kotlin/com/oksusu/susu/domain/post/infrastructure/repository/model/GetVoteSpec.kt index 6ccf204e..fd0cac7f 100644 --- a/domain/src/main/kotlin/com/oksusu/susu/domain/post/infrastructure/repository/model/GetVoteSpec.kt +++ b/domain/src/main/kotlin/com/oksusu/susu/domain/post/infrastructure/repository/model/GetVoteSpec.kt @@ -3,7 +3,7 @@ package com.oksusu.susu.domain.post.infrastructure.repository.model import org.springframework.data.domain.Pageable /** 투표 조회 조건 */ -class GetVoteSpec( +data class GetVoteSpec( /** 유저 id */ val uid: Long, /** 투표 검색 조건 */ diff --git a/domain/src/main/kotlin/com/oksusu/susu/domain/post/infrastructure/repository/model/PostAndUserModel.kt b/domain/src/main/kotlin/com/oksusu/susu/domain/post/infrastructure/repository/model/PostAndUserModel.kt index c57f41cb..84be1164 100644 --- a/domain/src/main/kotlin/com/oksusu/susu/domain/post/infrastructure/repository/model/PostAndUserModel.kt +++ b/domain/src/main/kotlin/com/oksusu/susu/domain/post/infrastructure/repository/model/PostAndUserModel.kt @@ -4,7 +4,7 @@ import com.oksusu.susu.domain.post.domain.Post import com.oksusu.susu.domain.user.domain.User import com.querydsl.core.annotations.QueryProjection -class PostAndUserModel @QueryProjection constructor( +data class PostAndUserModel @QueryProjection constructor( /** post */ val post: Post, /** user */ diff --git a/domain/src/main/kotlin/com/oksusu/susu/domain/post/infrastructure/repository/model/PostAndVoteCountModel.kt b/domain/src/main/kotlin/com/oksusu/susu/domain/post/infrastructure/repository/model/PostAndVoteCountModel.kt index 85f7b568..b1b0c6df 100644 --- a/domain/src/main/kotlin/com/oksusu/susu/domain/post/infrastructure/repository/model/PostAndVoteCountModel.kt +++ b/domain/src/main/kotlin/com/oksusu/susu/domain/post/infrastructure/repository/model/PostAndVoteCountModel.kt @@ -3,7 +3,7 @@ package com.oksusu.susu.domain.post.infrastructure.repository.model import com.oksusu.susu.domain.post.domain.Post import com.querydsl.core.annotations.QueryProjection -class PostAndVoteCountModel @QueryProjection constructor( +data class PostAndVoteCountModel @QueryProjection constructor( /** post */ val post: Post, /** vote count 수 */ diff --git a/domain/src/main/kotlin/com/oksusu/susu/domain/post/infrastructure/repository/model/PostAndVoteOptionModel.kt b/domain/src/main/kotlin/com/oksusu/susu/domain/post/infrastructure/repository/model/PostAndVoteOptionModel.kt index 40952926..f8df00f4 100644 --- a/domain/src/main/kotlin/com/oksusu/susu/domain/post/infrastructure/repository/model/PostAndVoteOptionModel.kt +++ b/domain/src/main/kotlin/com/oksusu/susu/domain/post/infrastructure/repository/model/PostAndVoteOptionModel.kt @@ -4,7 +4,7 @@ import com.oksusu.susu.domain.post.domain.Post import com.oksusu.susu.domain.post.domain.VoteOption import com.querydsl.core.annotations.QueryProjection -class PostAndVoteOptionModel @QueryProjection constructor( +data class PostAndVoteOptionModel @QueryProjection constructor( /** post */ val post: Post, /** vote option */ diff --git a/domain/src/main/kotlin/com/oksusu/susu/domain/post/infrastructure/repository/model/SearchVoteSpec.kt b/domain/src/main/kotlin/com/oksusu/susu/domain/post/infrastructure/repository/model/SearchVoteSpec.kt index 638995b5..567e2f67 100644 --- a/domain/src/main/kotlin/com/oksusu/susu/domain/post/infrastructure/repository/model/SearchVoteSpec.kt +++ b/domain/src/main/kotlin/com/oksusu/susu/domain/post/infrastructure/repository/model/SearchVoteSpec.kt @@ -1,7 +1,7 @@ package com.oksusu.susu.domain.post.infrastructure.repository.model /** 투표 검색 조건 */ -class SearchVoteSpec( +data class SearchVoteSpec( /** 검색 내용 */ val content: String?, /** 본인 소유 여부 */ diff --git a/domain/src/main/kotlin/com/oksusu/susu/domain/post/infrastructure/repository/model/VoteOptionAndCountModel.kt b/domain/src/main/kotlin/com/oksusu/susu/domain/post/infrastructure/repository/model/VoteOptionAndCountModel.kt index 3b65f67d..1556a1d0 100644 --- a/domain/src/main/kotlin/com/oksusu/susu/domain/post/infrastructure/repository/model/VoteOptionAndCountModel.kt +++ b/domain/src/main/kotlin/com/oksusu/susu/domain/post/infrastructure/repository/model/VoteOptionAndCountModel.kt @@ -3,7 +3,7 @@ package com.oksusu.susu.domain.post.infrastructure.repository.model import com.oksusu.susu.domain.post.domain.VoteOption import com.querydsl.core.annotations.QueryProjection -class VoteOptionAndCountModel @QueryProjection constructor( +data class VoteOptionAndCountModel @QueryProjection constructor( /** vote option */ val voteOption: VoteOption, /** vote option count 수 */