Skip to content
This repository was archived by the owner on Jul 7, 2025. It is now read-only.

Commit cf5837f

Browse files
authored
Merge pull request #129 from ASAP-Lettering/UMO-445
ASAP-445 네이버 access token 조회 api 추가
2 parents 827fd42 + 7f01df5 commit cf5837f

File tree

18 files changed

+281
-55
lines changed

18 files changed

+281
-55
lines changed
Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,22 @@
11
package com.asap.application.user.port.`in`
22

33
interface SocialLoginUsecase {
4-
54
fun login(command: Command): Response
65

76
data class Command(
87
val provider: String,
98
val accessToken: String,
109
)
1110

12-
sealed class Response {
13-
}
11+
sealed class Response
1412

1513
data class Success(
1614
val accessToken: String,
1715
val refreshToken: String,
18-
val isProcessedOnboarding: Boolean
16+
val isProcessedOnboarding: Boolean,
1917
) : Response()
2018

2119
data class NonRegistered(
22-
val registerToken: String
20+
val registerToken: String,
2321
) : Response()
24-
}
22+
}

Application-Module/src/main/kotlin/com/asap/application/user/port/out/AuthInfoRetrievePort.kt

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,15 @@ import com.asap.application.user.vo.AuthInfo
55
import com.asap.domain.user.enums.SocialLoginProvider
66

77
interface AuthInfoRetrievePort {
8-
98
@Throws(UserException.UserAuthNotFoundException::class)
10-
fun getAuthInfo(provider: SocialLoginProvider, accessToken: String): AuthInfo
11-
}
9+
fun getAuthInfo(
10+
provider: SocialLoginProvider,
11+
accessToken: String,
12+
): AuthInfo
13+
14+
fun getAccessToken(
15+
provider: SocialLoginProvider,
16+
code: String,
17+
state: String,
18+
): String
19+
}

Bootstrap-Module/src/main/kotlin/com/asap/bootstrap/web/auth/api/AuthApi.kt

Lines changed: 33 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,7 @@
11
package com.asap.bootstrap.web.auth.api
22

33
import com.asap.bootstrap.common.exception.ExceptionResponse
4-
import com.asap.bootstrap.web.auth.dto.ReissueRequest
5-
import com.asap.bootstrap.web.auth.dto.ReissueResponse
6-
import com.asap.bootstrap.web.auth.dto.SocialLoginRequest
7-
import com.asap.bootstrap.web.auth.dto.SocialLoginResponse
4+
import com.asap.bootstrap.web.auth.dto.*
85
import io.swagger.v3.oas.annotations.Operation
96
import io.swagger.v3.oas.annotations.media.Content
107
import io.swagger.v3.oas.annotations.media.Schema
@@ -62,6 +59,38 @@ interface AuthApi {
6259
@RequestBody request: SocialLoginRequest,
6360
): ResponseEntity<SocialLoginResponse>
6461

62+
@Operation(summary = "OAuth 액세스 토큰 획득")
63+
@PostMapping("/token/{provider}")
64+
@ApiResponses(
65+
value = [
66+
ApiResponse(
67+
responseCode = "200",
68+
description = "액세스 토큰 획득 성공",
69+
content = [
70+
Content(
71+
mediaType = "application/json",
72+
schema = Schema(implementation = OAuthAccessTokenResponse::class),
73+
),
74+
],
75+
),
76+
ApiResponse(
77+
responseCode = "4XX",
78+
description = "액세스 토큰 획득 실패",
79+
content = [
80+
Content(
81+
mediaType = "application/json",
82+
schema = Schema(implementation = ExceptionResponse::class),
83+
),
84+
],
85+
),
86+
],
87+
)
88+
fun getAccessToken(
89+
@Schema(description = "소셜 로그인 플랫폼, ex) KAKAO, GOOGLE, NAVER")
90+
@PathVariable provider: String,
91+
@RequestBody request: OAuthAccessTokenRequest,
92+
): OAuthAccessTokenResponse
93+
6594
@Operation(summary = "토큰 재발급")
6695
@PostMapping("/reissue")
6796
@ApiResponses(

Bootstrap-Module/src/main/kotlin/com/asap/bootstrap/web/auth/controller/AuthController.kt

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,10 @@ package com.asap.bootstrap.web.auth.controller
22

33
import com.asap.application.user.port.`in`.ReissueTokenUsecase
44
import com.asap.application.user.port.`in`.SocialLoginUsecase
5+
import com.asap.application.user.port.out.AuthInfoRetrievePort
56
import com.asap.bootstrap.web.auth.api.AuthApi
6-
import com.asap.bootstrap.web.auth.dto.ReissueRequest
7-
import com.asap.bootstrap.web.auth.dto.ReissueResponse
8-
import com.asap.bootstrap.web.auth.dto.SocialLoginRequest
9-
import com.asap.bootstrap.web.auth.dto.SocialLoginResponse
7+
import com.asap.bootstrap.web.auth.dto.*
8+
import com.asap.domain.user.enums.SocialLoginProvider
109
import org.springframework.http.HttpStatus
1110
import org.springframework.http.ResponseEntity
1211
import org.springframework.web.bind.annotation.RestController
@@ -15,6 +14,7 @@ import org.springframework.web.bind.annotation.RestController
1514
class AuthController(
1615
private val socialLoginUsecase: SocialLoginUsecase,
1716
private val reissueTokenUsecase: ReissueTokenUsecase,
17+
private val authInfoRetrievePort: AuthInfoRetrievePort,
1818
) : AuthApi {
1919
override fun socialLogin(
2020
provider: String,
@@ -54,4 +54,19 @@ class AuthController(
5454
refreshToken = response.refreshToken,
5555
)
5656
}
57+
58+
override fun getAccessToken(
59+
provider: String,
60+
request: OAuthAccessTokenRequest,
61+
): OAuthAccessTokenResponse {
62+
val accessToken =
63+
authInfoRetrievePort.getAccessToken(
64+
provider = SocialLoginProvider.valueOf(provider),
65+
code = request.code,
66+
state = request.state,
67+
)
68+
return OAuthAccessTokenResponse(
69+
accessToken = accessToken,
70+
)
71+
}
5772
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
package com.asap.bootstrap.web.auth.dto
2+
3+
data class OAuthAccessTokenRequest(
4+
val code: String,
5+
val state: String,
6+
)
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
package com.asap.bootstrap.web.auth.dto
2+
3+
data class OAuthAccessTokenResponse(
4+
val accessToken: String,
5+
)

Bootstrap-Module/src/main/resources/application.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,17 @@ spring:
55
- security
66
- aws
77
- persistence
8+
- client
89
local:
910
- security-local
1011
- aws-local
1112
- persistence-local
13+
- client-local
1214
test:
1315
- security-local
1416
- aws-local
1517
- persistence-test
18+
- client-local
1619
active: local
1720

1821

Bootstrap-Module/src/test/kotlin/com/asap/bootstrap/acceptance/auth/controller/AuthControllerTest.kt

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,12 @@ import com.asap.application.user.port.`in`.LogoutUsecase
44
import com.asap.application.user.port.`in`.ReissueTokenUsecase
55
import com.asap.application.user.port.`in`.SocialLoginUsecase
66
import com.asap.application.user.port.`in`.TokenResolveUsecase
7+
import com.asap.application.user.port.out.AuthInfoRetrievePort
78
import com.asap.bootstrap.AcceptanceSupporter
9+
import com.asap.bootstrap.web.auth.dto.OAuthAccessTokenRequest
810
import com.asap.bootstrap.web.auth.dto.ReissueRequest
911
import com.asap.bootstrap.web.auth.dto.SocialLoginRequest
12+
import com.asap.domain.user.enums.SocialLoginProvider
1013
import org.junit.jupiter.api.Test
1114
import org.mockito.BDDMockito
1215
import org.springframework.boot.test.mock.mockito.MockBean
@@ -26,6 +29,9 @@ class AuthControllerTest : AcceptanceSupporter() {
2629
@MockBean
2730
private lateinit var logoutUsecase: LogoutUsecase
2831

32+
@MockBean
33+
private lateinit var authInfoRetrievePort: AuthInfoRetrievePort
34+
2935
@Test
3036
fun socialLoginSuccessTest() {
3137
// given
@@ -112,4 +118,35 @@ class AuthControllerTest : AcceptanceSupporter() {
112118
}
113119
}
114120
}
121+
122+
@Test
123+
fun getAccessTokenTest() {
124+
// given
125+
val provider = "KAKAO"
126+
val code = "authorization_code"
127+
val state = "state"
128+
val request = OAuthAccessTokenRequest(code, state)
129+
val expectedAccessToken = "access_token"
130+
131+
BDDMockito
132+
.given(authInfoRetrievePort.getAccessToken(SocialLoginProvider.valueOf(provider), code, state))
133+
.willReturn(expectedAccessToken)
134+
135+
// when
136+
val response =
137+
mockMvc.post("/api/v1/auth/token/{provider}", provider) {
138+
contentType = MediaType.APPLICATION_JSON
139+
content = objectMapper.writeValueAsString(request)
140+
}
141+
142+
// then
143+
response.andExpect {
144+
status { isOk() }
145+
jsonPath("$.accessToken") {
146+
exists()
147+
isString()
148+
value(expectedAccessToken)
149+
}
150+
}
151+
}
115152
}
Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
package com.asap.client
22

3+
import org.springframework.boot.context.properties.EnableConfigurationProperties
34
import org.springframework.context.annotation.ComponentScan
45
import org.springframework.context.annotation.Configuration
56

67
@Configuration
78
@ComponentScan(basePackages = ["com.asap.client"])
8-
class ClientConfig {
9-
}
9+
@EnableConfigurationProperties(ClientProperties::class)
10+
class ClientConfig
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package com.asap.client
2+
3+
import org.springframework.boot.context.properties.ConfigurationProperties
4+
5+
@ConfigurationProperties(prefix = "client")
6+
class ClientProperties(
7+
var oauth: OAuthProperties = OAuthProperties(),
8+
)
9+
10+
class OAuthProperties(
11+
var naver: NaverOAuthProperties = NaverOAuthProperties(),
12+
)
13+
14+
class NaverOAuthProperties(
15+
var clientId: String = "",
16+
var clientSecret: String = "",
17+
)

0 commit comments

Comments
 (0)