Skip to content

Commit

Permalink
feat: dev resource를 resolver 기반으로 변경
Browse files Browse the repository at this point in the history
  • Loading branch information
DongGeon0908 committed Sep 1, 2024
1 parent d7c8f5a commit 317f795
Show file tree
Hide file tree
Showing 10 changed files with 143 additions and 55 deletions.
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
package com.hero.alignlab.config.dev

import com.hero.alignlab.domain.auth.model.DevAuthToken
import com.hero.alignlab.domain.auth.model.DevAuthUserImpl
import com.hero.alignlab.exception.ErrorCode
import com.hero.alignlab.exception.NoAuthorityException
import jakarta.validation.constraints.NotBlank
import org.springframework.boot.context.properties.ConfigurationProperties
import org.springframework.boot.context.properties.EnableConfigurationProperties
import org.springframework.context.annotation.Configuration
import reactor.core.publisher.Mono

@Configuration
@EnableConfigurationProperties(DevResourceCheckConfig.DevResourceCheckProperties::class)
Expand Down Expand Up @@ -34,4 +37,14 @@ class DevResourceCheckConfig(
throw NoAuthorityException(ErrorCode.NO_AUTHORITY_ERROR)
}
}

fun checkDev(token: Mono<DevAuthToken>): Mono<Any> {
return token.flatMap {
if (it.value != devResourceCheckProperties.key) {
Mono.error(NoAuthorityException(ErrorCode.NO_AUTHORITY_ERROR))
} else {
Mono.just(DevAuthUserImpl())
}
}
}
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
package com.hero.alignlab.config.swagger

import com.hero.alignlab.config.dev.DevResourceCheckConfig.Companion.DEV_AUTH_TOKEN_KEY
import com.hero.alignlab.domain.auth.model.AUTH_TOKEN_KEY
import com.hero.alignlab.domain.auth.model.AuthUser
import com.hero.alignlab.domain.auth.model.DEV_AUTH_TOKEN_KEY
import com.hero.alignlab.domain.auth.model.DevAuthUser
import io.swagger.v3.oas.models.Components
import io.swagger.v3.oas.models.OpenAPI
import io.swagger.v3.oas.models.info.Info
Expand Down Expand Up @@ -33,34 +34,40 @@ class SpringDocConfig(
.addRequestWrapperToIgnore(
WebSession::class.java,
RequestContext::class.java,
AuthUser::class.java
AuthUser::class.java,
DevAuthUser::class.java,
)
}

@Bean
fun openApi(): OpenAPI {
val securityRequirement = SecurityRequirement().addList(AUTH_TOKEN_KEY)
return OpenAPI()
.components(authSetting())
.security(listOf(securityRequirement))
.addServersItem(Server().url("/"))
.info(
Info()
.title(buildProperties.name)
.version(buildProperties.version)
.description("Hero Alignlab Rest API Docs")
)
.addSecurityItem(SecurityRequirement().addList(AUTH_TOKEN_KEY))
.addSecurityItem(SecurityRequirement().addList(DEV_AUTH_TOKEN_KEY))
}

private fun authSetting(): Components {
return Components()
.addSecuritySchemes(
AUTH_TOKEN_KEY,
SecurityScheme()
.description("Access Token")
.name(AUTH_TOKEN_KEY)
.type(SecurityScheme.Type.APIKEY)
.`in`(SecurityScheme.In.HEADER)
).addSecuritySchemes(
DEV_AUTH_TOKEN_KEY,
SecurityScheme()
.name(DEV_AUTH_TOKEN_KEY)
.type(SecurityScheme.Type.APIKEY)
.`in`(SecurityScheme.In.HEADER)
.name(AUTH_TOKEN_KEY)
)
}
}
Expand Down
4 changes: 4 additions & 0 deletions src/main/kotlin/com/hero/alignlab/config/web/WebFluxConfig.kt
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package com.hero.alignlab.config.web

import com.fasterxml.jackson.databind.ObjectMapper
import com.hero.alignlab.config.dev.DevResourceCheckConfig
import com.hero.alignlab.domain.auth.application.AuthFacade
import com.hero.alignlab.domain.auth.resolver.ReactiveDevResolver
import com.hero.alignlab.domain.auth.resolver.ReactiveUserResolver
import org.springframework.context.annotation.Configuration
import org.springframework.core.ReactiveAdapterRegistry
Expand All @@ -23,6 +25,7 @@ import java.nio.charset.Charset
class WebFluxConfig(
private val objectMapper: ObjectMapper,
private val authFacade: AuthFacade,
private val devResourceCheckConfig: DevResourceCheckConfig,
) : WebFluxConfigurer {
override fun addCorsMappings(registry: CorsRegistry) {
registry.addMapping("/**")
Expand Down Expand Up @@ -51,6 +54,7 @@ class WebFluxConfig(

configurer.addCustomResolver(
ReactiveUserResolver(registry, authFacade),
ReactiveDevResolver(registry, devResourceCheckConfig),
ReactiveSortHandlerMethodArgumentResolver(),
ReactivePageableHandlerMethodArgumentResolver()
)
Expand Down
37 changes: 37 additions & 0 deletions src/main/kotlin/com/hero/alignlab/domain/auth/model/DevAuthUser.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package com.hero.alignlab.domain.auth.model

import com.hero.alignlab.exception.ErrorCode
import com.hero.alignlab.exception.NotFoundException
import org.springframework.http.HttpHeaders

const val DEV_AUTH_TOKEN_KEY = "X-HERO-DEV-TOKEN"

interface DevAuthUser

class DevAuthUserImpl : DevAuthUser

data class DevAuthToken(
val key: String = DEV_AUTH_TOKEN_KEY,
val value: String,
) {
companion object {
fun HttpHeaders.resolveDevToken(): DevAuthToken {
return this.asSequence()
.filter { header -> isTokenHeader(header.key) }
.mapNotNull { header ->
header.value
.firstOrNull()
?.takeIf { token -> token.isNotBlank() }
?.let { token -> from(token) }
}.firstOrNull() ?: throw NotFoundException(ErrorCode.NOT_FOUND_TOKEN_ERROR)
}

private fun isTokenHeader(headerKey: String): Boolean {
return DEV_AUTH_TOKEN_KEY.equals(headerKey, ignoreCase = true)
}

private fun from(value: String): DevAuthToken {
return DevAuthToken(value = value)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package com.hero.alignlab.domain.auth.resolver

import com.hero.alignlab.config.dev.DevResourceCheckConfig
import com.hero.alignlab.domain.auth.model.DevAuthToken
import com.hero.alignlab.domain.auth.model.DevAuthToken.Companion.resolveDevToken
import com.hero.alignlab.domain.auth.model.DevAuthUser
import org.springframework.core.MethodParameter
import org.springframework.core.ReactiveAdapterRegistry
import org.springframework.http.server.reactive.ServerHttpRequest
import org.springframework.web.reactive.BindingContext
import org.springframework.web.reactive.result.method.HandlerMethodArgumentResolverSupport
import org.springframework.web.server.ServerWebExchange
import reactor.core.publisher.Mono
import reactor.kotlin.core.publisher.toMono

class ReactiveDevResolver(
adapterRegistry: ReactiveAdapterRegistry,
private val devResourceCheckConfig: DevResourceCheckConfig,
) : HandlerMethodArgumentResolverSupport(adapterRegistry) {
override fun supportsParameter(parameter: MethodParameter): Boolean {
return parameter.parameterType == DevAuthUser::class.java
}

override fun resolveArgument(
parameter: MethodParameter,
bindingContext: BindingContext,
exchange: ServerWebExchange,
): Mono<Any> {
val tokenMono = resolveToken(exchange.request)

return devResourceCheckConfig.checkDev(tokenMono)
}

private fun resolveToken(request: ServerHttpRequest): Mono<DevAuthToken> {
return request.headers
.resolveDevToken()
.toMono()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,15 @@ package com.hero.alignlab.domain.dev.resource
import com.hero.alignlab.batch.statistics.job.HeroStatisticsJob
import com.hero.alignlab.client.discord.client.DiscordWebhookClient
import com.hero.alignlab.client.discord.model.request.SendMessageRequest
import com.hero.alignlab.config.dev.DevResourceCheckConfig.Companion.devResource
import com.hero.alignlab.config.swagger.SwaggerTag.DEV_TAG
import com.hero.alignlab.domain.auth.model.DevAuthUser
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.*
import org.springframework.web.bind.annotation.PostMapping
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RequestParam
import org.springframework.web.bind.annotation.RestController
import java.time.LocalDateTime

@Tag(name = DEV_TAG)
Expand All @@ -21,23 +24,19 @@ class DevDiscordWebhookResource(
@Operation(summary = "discord webhook test")
@PostMapping("/api/dev/v1/discord-webhooks/{id}")
suspend fun sendMessage(
@RequestHeader("X-HERO-DEV-TOKEN") token: String,
dev: DevAuthUser,
@RequestParam message: String,
) = devResource(token) {
discordWebhookClient.sendMessage(SendMessageRequest(message))
}
) = discordWebhookClient.sendMessage(SendMessageRequest(message))

@Operation(summary = "discord webhook daily noti")
@PostMapping("/api/dev/v1/discord-webhooks/daily-noti")
suspend fun sendDailyNoti(
@RequestHeader("X-HERO-DEV-TOKEN") token: String,
dev: DevAuthUser,
@RequestParam fromDateTime: LocalDateTime,
@RequestParam toDateTime: LocalDateTime,
) = devResource(token) {
statisticsJob.sendHeroStatistics(
title = "극락통계 테스트",
fromDate = fromDateTime,
toDate = toDateTime
)
}
) = statisticsJob.sendHeroStatistics(
title = "극락통계 테스트",
fromDate = fromDateTime,
toDate = toDateTime
)
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package com.hero.alignlab.domain.dev.resource

import com.hero.alignlab.config.dev.DevResourceCheckConfig.Companion.devResource
import com.hero.alignlab.config.swagger.SwaggerTag.DEV_TAG
import com.hero.alignlab.domain.auth.model.DevAuthUser
import com.hero.alignlab.domain.dev.model.request.DevGroupJoinRequest
import com.hero.alignlab.domain.group.application.GroupFacade
import io.swagger.v3.oas.annotations.Operation
Expand All @@ -18,14 +18,12 @@ class DevGroupResource(
@Operation(summary = "그룹 조인하기")
@PostMapping("/api/dev/v1/groups/{groupId}/join")
suspend fun joinGroup(
@RequestHeader("X-HERO-DEV-TOKEN") token: String,
dev: DevAuthUser,
@PathVariable groupId: Long,
@RequestBody request: DevGroupJoinRequest,
) = devResource(token) {
groupFacade.joinGroup(
groupId = groupId,
uid = request.uid,
joinCode = request.joinCode
)
}
) = groupFacade.joinGroup(
groupId = groupId,
uid = request.uid,
joinCode = request.joinCode
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ package com.hero.alignlab.domain.dev.resource

import com.hero.alignlab.batch.posecount.job.PoseCountUpdateJob
import com.hero.alignlab.common.extension.wrapVoid
import com.hero.alignlab.config.dev.DevResourceCheckConfig.Companion.devResource
import com.hero.alignlab.config.swagger.SwaggerTag.DEV_TAG
import com.hero.alignlab.domain.auth.model.DevAuthUser
import com.hero.alignlab.domain.dev.application.DevPoseService
import com.hero.alignlab.domain.dev.model.request.DevPoseSnapshotRequest
import io.swagger.v3.oas.annotations.Operation
Expand All @@ -22,26 +22,20 @@ class DevPoseResource(
@Operation(summary = "[DEV] 포즈 스냅샷 생성")
@PostMapping("/api/dev/v1/pose-snapshots")
suspend fun createPoseSnapshots(
@RequestHeader("X-HERO-DEV-TOKEN") token: String,
dev: DevAuthUser,
@RequestBody request: DevPoseSnapshotRequest,
) = devResource(token) {
devPoseService.create(request).wrapVoid()
}
) = devPoseService.create(request).wrapVoid()

@Operation(summary = "[DEV] 포즈 데이터 삭제")
@DeleteMapping("/api/dev/v1/pose-snapshots/{id}")
suspend fun deletePoseSnapshots(
@RequestHeader("X-HERO-DEV-TOKEN") token: String,
) = devResource(token) {
devPoseService.deleteAllPoseData()
}
dev: DevAuthUser,
) = devPoseService.deleteAllPoseData()

@Operation(summary = "[DEV] 포즈 데이터 통계 처리")
@PostMapping("/api/dev/v1/pose-counts")
suspend fun updatePoseCounts(
@RequestHeader("X-HERO-DEV-TOKEN") token: String,
dev: DevAuthUser,
@RequestParam targetDate: LocalDate
) = devResource(token) {
poseCountUpdateJob.run(targetDate)
}
) = poseCountUpdateJob.run(targetDate)
}
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
package com.hero.alignlab.domain.dev.resource

import com.hero.alignlab.common.extension.wrapOk
import com.hero.alignlab.config.dev.DevResourceCheckConfig.Companion.devResource
import com.hero.alignlab.config.swagger.SwaggerTag.DEV_TAG
import com.hero.alignlab.domain.auth.model.DevAuthUser
import com.hero.alignlab.domain.user.application.UserInfoService
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.*
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.PathVariable
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RestController

@Tag(name = DEV_TAG)
@RestController
Expand All @@ -18,9 +20,7 @@ class DevUserInfoResource(
@Operation(summary = "[DEV] 유저 정보 조회")
@GetMapping("/api/dev/v1/users/{id}")
suspend fun getUserInfo(
dev: DevAuthUser,
@PathVariable id: Long,
@RequestHeader("X-HERO-DEV-TOKEN") token: String
) = devResource(token) {
userInfoService.getUserInfo(id).wrapOk()
}
) = userInfoService.getUserInfo(id)
}
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
package com.hero.alignlab.domain.dev.resource

import com.hero.alignlab.config.dev.DevResourceCheckConfig.Companion.devResource
import com.hero.alignlab.config.swagger.SwaggerTag.DEV_TAG
import com.hero.alignlab.domain.auth.model.DevAuthUser
import com.hero.alignlab.domain.dev.application.DevWebsocketService
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.PostMapping
import org.springframework.web.bind.annotation.RequestHeader
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RestController

Expand All @@ -20,8 +19,6 @@ class DevWebsocketResource(
@Operation(summary = "[DEV] websocket connection closed")
@PostMapping("/api/dev/v1/websocket/connection-closed")
suspend fun closedConnection(
@RequestHeader("X-HERO-DEV-TOKEN") token: String
) = devResource(token) {
devWebsocketService.forceCloseAllWebSocketSessions()
}
dev: DevAuthUser,
) = devWebsocketService.forceCloseAllWebSocketSessions()
}

0 comments on commit 317f795

Please sign in to comment.