diff --git a/src/main/kotlin/com/moa/common/auth/AdminAuth.kt b/src/main/kotlin/com/moa/common/auth/AdminAuth.kt new file mode 100644 index 0000000..288e5eb --- /dev/null +++ b/src/main/kotlin/com/moa/common/auth/AdminAuth.kt @@ -0,0 +1,5 @@ +package com.moa.common.auth + +@Target(AnnotationTarget.FUNCTION) +@Retention(AnnotationRetention.RUNTIME) +annotation class AdminAuth diff --git a/src/main/kotlin/com/moa/common/auth/AdminAuthInterceptor.kt b/src/main/kotlin/com/moa/common/auth/AdminAuthInterceptor.kt new file mode 100644 index 0000000..d77ef45 --- /dev/null +++ b/src/main/kotlin/com/moa/common/auth/AdminAuthInterceptor.kt @@ -0,0 +1,28 @@ +package com.moa.common.auth + +import com.moa.common.exception.UnauthorizedException +import jakarta.servlet.http.HttpServletRequest +import jakarta.servlet.http.HttpServletResponse +import org.springframework.stereotype.Component +import org.springframework.web.method.HandlerMethod +import org.springframework.web.servlet.HandlerInterceptor + +@Component +class AdminAuthInterceptor( + private val adminProperties: AdminProperties, +) : HandlerInterceptor { + + override fun preHandle(request: HttpServletRequest, response: HttpServletResponse, handler: Any): Boolean { + if (handler is HandlerMethod && handler.hasMethodAnnotation(AdminAuth::class.java)) { + val key = request.getHeader(ADMIN_KEY_HEADER) + if (key != adminProperties.apiKey) { + throw UnauthorizedException() + } + } + return true + } + + companion object { + private const val ADMIN_KEY_HEADER = "X-Admin-Key" + } +} diff --git a/src/main/kotlin/com/moa/common/auth/AdminProperties.kt b/src/main/kotlin/com/moa/common/auth/AdminProperties.kt new file mode 100644 index 0000000..822a8d4 --- /dev/null +++ b/src/main/kotlin/com/moa/common/auth/AdminProperties.kt @@ -0,0 +1,8 @@ +package com.moa.common.auth + +import org.springframework.boot.context.properties.ConfigurationProperties + +@ConfigurationProperties(prefix = "admin") +data class AdminProperties( + val apiKey: String, +) diff --git a/src/main/kotlin/com/moa/common/config/SwaggerConfig.kt b/src/main/kotlin/com/moa/common/config/SwaggerConfig.kt index 8d81df2..860f688 100644 --- a/src/main/kotlin/com/moa/common/config/SwaggerConfig.kt +++ b/src/main/kotlin/com/moa/common/config/SwaggerConfig.kt @@ -35,8 +35,17 @@ class SwaggerConfig { .bearerFormat(jwt) .`in`(SecurityScheme.In.HEADER) + val adminKeyScheme = SecurityScheme() + .name("X-Admin-Key") + .type(SecurityScheme.Type.APIKEY) + .`in`(SecurityScheme.In.HEADER) + return OpenAPI() - .components(Components().addSecuritySchemes(securitySchemeName, securityScheme)) + .components( + Components() + .addSecuritySchemes(securitySchemeName, securityScheme) + .addSecuritySchemes("AdminKey", adminKeyScheme) + ) .addSecurityItem(securityRequirement) .servers( listOf( diff --git a/src/main/kotlin/com/moa/common/config/WebConfig.kt b/src/main/kotlin/com/moa/common/config/WebConfig.kt index e3b0c08..a0bcd21 100644 --- a/src/main/kotlin/com/moa/common/config/WebConfig.kt +++ b/src/main/kotlin/com/moa/common/config/WebConfig.kt @@ -1,17 +1,24 @@ package com.moa.common.config +import com.moa.common.auth.AdminAuthInterceptor import com.moa.common.auth.AuthMemberResolver import com.moa.common.auth.OnboardingAuthMemberResolver import org.springframework.context.annotation.Configuration import org.springframework.web.method.support.HandlerMethodArgumentResolver +import org.springframework.web.servlet.config.annotation.InterceptorRegistry import org.springframework.web.servlet.config.annotation.WebMvcConfigurer @Configuration class WebConfig( private val onboardingAuthMemberResolver: OnboardingAuthMemberResolver, private val authMemberResolver: AuthMemberResolver, + private val adminAuthInterceptor: AdminAuthInterceptor, ) : WebMvcConfigurer { + override fun addInterceptors(registry: InterceptorRegistry) { + registry.addInterceptor(adminAuthInterceptor) + } + override fun addArgumentResolvers(resolvers: MutableList) { resolvers.add(onboardingAuthMemberResolver) resolvers.add(authMemberResolver) diff --git a/src/main/kotlin/com/moa/controller/VersionController.kt b/src/main/kotlin/com/moa/controller/VersionController.kt index 7c0ad68..fc3cb68 100644 --- a/src/main/kotlin/com/moa/controller/VersionController.kt +++ b/src/main/kotlin/com/moa/controller/VersionController.kt @@ -1,10 +1,15 @@ package com.moa.controller +import com.moa.common.auth.AdminAuth import com.moa.common.response.ApiResponse import com.moa.entity.OsType import com.moa.service.AppVersionService +import com.moa.service.dto.AppVersionUpdateRequest +import io.swagger.v3.oas.annotations.security.SecurityRequirement import io.swagger.v3.oas.annotations.tags.Tag import org.springframework.web.bind.annotation.GetMapping +import org.springframework.web.bind.annotation.PutMapping +import org.springframework.web.bind.annotation.RequestBody import org.springframework.web.bind.annotation.RequestMapping import org.springframework.web.bind.annotation.RequestParam import org.springframework.web.bind.annotation.RestController @@ -19,4 +24,10 @@ class VersionController( @GetMapping fun getVersion(@RequestParam osType: OsType) = ApiResponse.success(appVersionService.getVersion(osType)) + + @AdminAuth + @SecurityRequirement(name = "AdminKey") + @PutMapping + fun updateVersion(@RequestBody request: AppVersionUpdateRequest) = + ApiResponse.success(appVersionService.updateVersion(request)) } diff --git a/src/main/kotlin/com/moa/service/AppVersionService.kt b/src/main/kotlin/com/moa/service/AppVersionService.kt index e3cc57b..f0b576d 100644 --- a/src/main/kotlin/com/moa/service/AppVersionService.kt +++ b/src/main/kotlin/com/moa/service/AppVersionService.kt @@ -4,6 +4,7 @@ import com.moa.common.exception.NotFoundException import com.moa.entity.OsType import com.moa.repository.AppVersionRepository import com.moa.service.dto.AppVersionResponse +import com.moa.service.dto.AppVersionUpdateRequest import org.springframework.stereotype.Service import org.springframework.transaction.annotation.Transactional @@ -21,4 +22,16 @@ class AppVersionService( minimumVersion = version.minimumVersion, ) } + + @Transactional + fun updateVersion(request: AppVersionUpdateRequest): AppVersionResponse { + val version = appVersionRepository.findByOsType(request.osType) + ?: throw NotFoundException() + version.latestVersion = request.latestVersion + version.minimumVersion = request.minimumVersion + return AppVersionResponse( + latestVersion = version.latestVersion, + minimumVersion = version.minimumVersion, + ) + } } diff --git a/src/main/kotlin/com/moa/service/dto/AppVersionUpdateRequest.kt b/src/main/kotlin/com/moa/service/dto/AppVersionUpdateRequest.kt new file mode 100644 index 0000000..5aae837 --- /dev/null +++ b/src/main/kotlin/com/moa/service/dto/AppVersionUpdateRequest.kt @@ -0,0 +1,9 @@ +package com.moa.service.dto + +import com.moa.entity.OsType + +data class AppVersionUpdateRequest( + val osType: OsType, + val latestVersion: String, + val minimumVersion: String, +) diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index e9388a1..f2c3bdf 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -4,6 +4,7 @@ spring: - moa-secret/oauth.yml - moa-secret/jwt.yml - moa-secret/db.yml + - moa-secret/admin.yml profiles: default: local diff --git a/src/main/resources/moa-secret b/src/main/resources/moa-secret index 31eefb0..eb8f409 160000 --- a/src/main/resources/moa-secret +++ b/src/main/resources/moa-secret @@ -1 +1 @@ -Subproject commit 31eefb03eded643e9c95c03280c1d00d22204d65 +Subproject commit eb8f4099a5d560012157557348e892bbeea804c8