Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 0 additions & 4 deletions src/main/kotlin/com/moa/common/auth/Auth.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,3 @@ package com.moa.common.auth
@Target(AnnotationTarget.VALUE_PARAMETER)
@Retention(AnnotationRetention.RUNTIME)
annotation class Auth

data class AuthenticatedMemberInfo(
val id: Long,
)
5 changes: 0 additions & 5 deletions src/main/kotlin/com/moa/common/auth/AuthConstants.kt

This file was deleted.

5 changes: 5 additions & 0 deletions src/main/kotlin/com/moa/common/auth/AuthMemberInfo.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package com.moa.common.auth

data class AuthMemberInfo(
val id: Long,
)
105 changes: 105 additions & 0 deletions src/main/kotlin/com/moa/common/auth/AuthMemberResolver.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
package com.moa.common.auth

import com.moa.common.exception.ErrorCode
import com.moa.common.exception.ForbiddenException
import com.moa.common.exception.UnauthorizedException
import com.moa.repository.*
import io.jsonwebtoken.ExpiredJwtException
import jakarta.servlet.http.HttpServletRequest
import org.springframework.core.MethodParameter
import org.springframework.stereotype.Component
import org.springframework.web.bind.support.WebDataBinderFactory
import org.springframework.web.context.request.NativeWebRequest
import org.springframework.web.method.support.HandlerMethodArgumentResolver
import org.springframework.web.method.support.ModelAndViewContainer
import java.time.LocalDate

@Component
class AuthMemberResolver(
private val jwtTokenProvider: JwtTokenProvider,
private val request: HttpServletRequest,
private val termRepository: TermRepository,
private val termAgreementRepository: TermAgreementRepository,
private val profileRepository: ProfileRepository,
private val payrollVersionRepository: PayrollVersionRepository,
private val workPolicyVersionRepository: WorkPolicyVersionRepository,
) : HandlerMethodArgumentResolver {

override fun supportsParameter(parameter: MethodParameter): Boolean {
return parameter.hasParameterAnnotation(Auth::class.java) &&
parameter.parameterType == AuthMemberInfo::class.java
}

override fun resolveArgument(
parameter: MethodParameter,
mavContainer: ModelAndViewContainer?,
webRequest: NativeWebRequest,
binderFactory: WebDataBinderFactory?,
): AuthMemberInfo {
val memberId = resolveMemberId()
validateOnboardingCompleted(memberId)
return AuthMemberInfo(id = memberId)
}

private fun resolveMemberId(): Long {
val token = jwtTokenProvider.extractToken(request)
?: throw UnauthorizedException()

return try {
jwtTokenProvider.validateToken(token)
jwtTokenProvider.getUserIdFromToken(token)
} catch (ex: ExpiredJwtException) {
throw UnauthorizedException(ErrorCode.EXPIRED_TOKEN)
} catch (ex: Exception) {
throw UnauthorizedException()
} ?: throw UnauthorizedException()
}

private fun validateOnboardingCompleted(memberId: Long) {
val today = LocalDate.now()

val profileCompleted = isProfileCompleted(memberId)
val payrollCompleted = isPayrollCompleted(memberId, today)
val workPolicyCompleted = isWorkPolicyCompleted(memberId, today)
val hasRequiredTermsAgreed = hasRequiredTermsAgreed(memberId)

val onboardingCompleted =
profileCompleted && payrollCompleted && workPolicyCompleted && hasRequiredTermsAgreed

if (!onboardingCompleted) {
throw ForbiddenException(ErrorCode.ONBOARDING_INCOMPLETE)
}
}

private fun isProfileCompleted(memberId: Long): Boolean {
return profileRepository.findByMemberId(memberId)
?.let { it.nickname.isNotBlank() && it.workplace.isNotBlank() }
?: false
}

private fun isPayrollCompleted(memberId: Long, today: LocalDate): Boolean {
return payrollVersionRepository
.findTopByMemberIdAndEffectiveFromLessThanEqualOrderByEffectiveFromDesc(memberId, today) != null
}

private fun isWorkPolicyCompleted(memberId: Long, today: LocalDate): Boolean {
return workPolicyVersionRepository
.findTopByMemberIdAndEffectiveFromLessThanEqualOrderByEffectiveFromDesc(memberId, today)
?.workdays
?.isNotEmpty()
?: false
}

private fun hasRequiredTermsAgreed(memberId: Long): Boolean {
val requiredCodes = termRepository.findAll()
.asSequence()
.filter { it.required }
.map { it.code }
.toSet()

val agreements = termAgreementRepository.findAllByMemberId(memberId)
.associate { it.termCode to it.agreed }

return requiredCodes.all { agreements[it] == true }
}
}
34 changes: 0 additions & 34 deletions src/main/kotlin/com/moa/common/auth/AuthenticatedMemberResolver.kt

This file was deleted.

5 changes: 5 additions & 0 deletions src/main/kotlin/com/moa/common/auth/OnboardingAuth.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package com.moa.common.auth

@Target(AnnotationTarget.VALUE_PARAMETER)
@Retention(AnnotationRetention.RUNTIME)
annotation class OnboardingAuth
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package com.moa.common.auth

import com.moa.common.exception.ErrorCode
import com.moa.common.exception.UnauthorizedException
import io.jsonwebtoken.ExpiredJwtException
import jakarta.servlet.http.HttpServletRequest
import org.springframework.core.MethodParameter
import org.springframework.stereotype.Component
import org.springframework.web.bind.support.WebDataBinderFactory
import org.springframework.web.context.request.NativeWebRequest
import org.springframework.web.method.support.HandlerMethodArgumentResolver
import org.springframework.web.method.support.ModelAndViewContainer

@Component
class OnboardingAuthMemberResolver(
private val jwtTokenProvider: JwtTokenProvider,
private val request: HttpServletRequest,
) : HandlerMethodArgumentResolver {

override fun supportsParameter(parameter: MethodParameter): Boolean {
return parameter.hasParameterAnnotation(OnboardingAuth::class.java) &&
parameter.parameterType == AuthMemberInfo::class.java
}

override fun resolveArgument(
parameter: MethodParameter,
mavContainer: ModelAndViewContainer?,
webRequest: NativeWebRequest,
binderFactory: WebDataBinderFactory?,
): AuthMemberInfo {
val token = jwtTokenProvider.extractToken(request)
?: throw UnauthorizedException()

try {
jwtTokenProvider.validateToken(token)

val memberId = jwtTokenProvider.getUserIdFromToken(token)
?: throw UnauthorizedException()

return AuthMemberInfo(id = memberId)
} catch (ex: ExpiredJwtException) {
throw UnauthorizedException(ErrorCode.EXPIRED_TOKEN)
} catch (ex: Exception) {
throw UnauthorizedException()
}
}
}
5 changes: 4 additions & 1 deletion src/main/kotlin/com/moa/common/config/SwaggerConfig.kt
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.moa.common.config

import com.moa.common.auth.Auth
import com.moa.common.auth.OnboardingAuth
import io.swagger.v3.oas.models.Components
import io.swagger.v3.oas.models.OpenAPI
import io.swagger.v3.oas.models.info.Info
Expand All @@ -15,7 +16,9 @@ import org.springframework.context.annotation.Configuration
class SwaggerConfig {

init {
SpringDocUtils.getConfig().addAnnotationsToIgnore(Auth::class.java)
SpringDocUtils.getConfig()
.addAnnotationsToIgnore(OnboardingAuth::class.java)
.addAnnotationsToIgnore(Auth::class.java)
}

@Bean
Expand Down
9 changes: 6 additions & 3 deletions src/main/kotlin/com/moa/common/config/WebConfig.kt
Original file line number Diff line number Diff line change
@@ -1,16 +1,19 @@
package com.moa.common.config

import com.moa.common.auth.AuthenticatedMemberResolver
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.WebMvcConfigurer

@Configuration
class WebConfig(
private val authenticatedMemberResolver: AuthenticatedMemberResolver,
private val onboardingAuthMemberResolver: OnboardingAuthMemberResolver,
private val authMemberResolver: AuthMemberResolver,
) : WebMvcConfigurer {

override fun addArgumentResolvers(resolvers: MutableList<HandlerMethodArgumentResolver>) {
resolvers.add(authenticatedMemberResolver)
resolvers.add(onboardingAuthMemberResolver)
resolvers.add(authMemberResolver)
}
}
2 changes: 1 addition & 1 deletion src/main/kotlin/com/moa/common/exception/ErrorCode.kt
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ enum class ErrorCode(
// 4xx
BAD_REQUEST("BAD_REQUEST", "잘못된 요청입니다."),
UNAUTHORIZED("UNAUTHORIZED", "인증되지 않은 사용자입니다"),
FORBIDDEN("FORBIDDEN", "권한이 없습니다"),
ONBOARDING_INCOMPLETE("ONBOARDING_INCOMPLETE", "온보딩이 완료되지 않았습니다"),
RESOURCE_NOT_FOUND("RESOURCE_NOT_FOUND", "리소스를 찾을 수 없습니다"),

INVALID_PAYROLL_INPUT("INVALID_PAYROLL_INPUT", "급여 입력값이 유효하지 않습니다"),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
package com.moa.common.exception

class ForbiddenException(
val errorCode: ErrorCode = ErrorCode.FORBIDDEN,
val errorCode: ErrorCode,
) : RuntimeException(errorCode.message)
79 changes: 0 additions & 79 deletions src/main/kotlin/com/moa/common/filter/JwtAuthenticationFilter.kt

This file was deleted.

Loading
Loading