diff --git a/dongne-account-api/src/main/kotlin/io/beaniejoy/dongnecafe/common/config/SecurityConfig.kt b/dongne-account-api/src/main/kotlin/io/beaniejoy/dongnecafe/common/config/SecurityConfig.kt index 8ecd601..ca04bc2 100644 --- a/dongne-account-api/src/main/kotlin/io/beaniejoy/dongnecafe/common/config/SecurityConfig.kt +++ b/dongne-account-api/src/main/kotlin/io/beaniejoy/dongnecafe/common/config/SecurityConfig.kt @@ -22,7 +22,6 @@ class SecurityConfig { .authorizeRequests() .antMatchers("/auth/members/sign-up").permitAll() .antMatchers("/auth/authenticate").permitAll() - .antMatchers("/test").hasRole("USER") // 임시 인가 테스트용 .anyRequest().authenticated() .and() diff --git a/dongne-account-api/src/main/kotlin/io/beaniejoy/dongnecafe/common/security/UserDetailsServiceImpl.kt b/dongne-account-api/src/main/kotlin/io/beaniejoy/dongnecafe/common/security/UserDetailsServiceImpl.kt index 970cc3f..b0259bb 100644 --- a/dongne-account-api/src/main/kotlin/io/beaniejoy/dongnecafe/common/security/UserDetailsServiceImpl.kt +++ b/dongne-account-api/src/main/kotlin/io/beaniejoy/dongnecafe/common/security/UserDetailsServiceImpl.kt @@ -22,7 +22,7 @@ class UserDetailsServiceImpl( return memberRepository.findByEmail(email)?.let { logger.info { "[LOAD MEMBER] email: ${it.email}, role: ${it.roleType}, activated: ${it.activated}" } createSecurityUser(it) - } ?: throw UsernameNotFoundException(email) + } ?: throw UsernameNotFoundException("${email} is not found") } private fun createSecurityUser(member: Member): SecurityUser { diff --git a/dongne-account-api/src/main/kotlin/io/beaniejoy/dongnecafe/controller/TestController.kt b/dongne-account-api/src/main/kotlin/io/beaniejoy/dongnecafe/controller/TestController.kt deleted file mode 100644 index b171393..0000000 --- a/dongne-account-api/src/main/kotlin/io/beaniejoy/dongnecafe/controller/TestController.kt +++ /dev/null @@ -1,13 +0,0 @@ -package io.beaniejoy.dongnecafe.controller - -import org.springframework.web.bind.annotation.GetMapping -import org.springframework.web.bind.annotation.RestController - -@RestController -class TestController { - - @GetMapping("/test") - fun test(): String { - return "authorize OK!" - } -} \ No newline at end of file diff --git a/dongne-account-api/src/main/kotlin/io/beaniejoy/dongnecafe/error/handler/CommonControllerAdvice.kt b/dongne-account-api/src/main/kotlin/io/beaniejoy/dongnecafe/error/handler/CommonControllerAdvice.kt new file mode 100644 index 0000000..83d901c --- /dev/null +++ b/dongne-account-api/src/main/kotlin/io/beaniejoy/dongnecafe/error/handler/CommonControllerAdvice.kt @@ -0,0 +1,27 @@ +package io.beaniejoy.dongnecafe.error.handler + +import io.beaniejoy.dongnecafe.error.ErrorResponse +import mu.KLogging +import org.springframework.http.HttpStatus +import org.springframework.http.ResponseEntity +import org.springframework.security.core.AuthenticationException +import org.springframework.web.bind.annotation.ExceptionHandler +import org.springframework.web.bind.annotation.RestControllerAdvice + +// TODO 통합된 에러 핸들링 필요(ErrorResponse 규격화) +@RestControllerAdvice +class CommonControllerAdvice { + + companion object : KLogging() + + @ExceptionHandler(AuthenticationException::class) + fun handleAuthenticationException(e: AuthenticationException): ResponseEntity { + logger.error { "AuthenticationException: ${e.message}" } + return ResponseEntity.ok().body( + ErrorResponse( + code = HttpStatus.BAD_REQUEST.value(), + message = "계정 혹은 비밀번호가 일치하지 않습니다." + ) + ) + } +} \ No newline at end of file diff --git a/dongne-account-api/src/main/resources/application-local.yml b/dongne-account-api/src/main/resources/application-local.yml index 58a0493..eafd9db 100644 --- a/dongne-account-api/src/main/resources/application-local.yml +++ b/dongne-account-api/src/main/resources/application-local.yml @@ -5,4 +5,4 @@ spring: password: beaniejoy # TODO 추후 보안에 대해 생각해보기 jwt: secret_key: aG9wZS15b3UtYWx3YXlzLWJlLWhhcHB5LXRoaXMteWVhcgo= - expiration_time: 86400 \ No newline at end of file + validity_time_in_sec: 86400 \ No newline at end of file diff --git a/dongne-common/src/main/kotlin/io/beaniejoy/dongnecafe/error/ErrorResponse.kt b/dongne-common/src/main/kotlin/io/beaniejoy/dongnecafe/error/ErrorResponse.kt new file mode 100644 index 0000000..a6e8abd --- /dev/null +++ b/dongne-common/src/main/kotlin/io/beaniejoy/dongnecafe/error/ErrorResponse.kt @@ -0,0 +1,6 @@ +package io.beaniejoy.dongnecafe.error + +data class ErrorResponse( + val code: Int, + val message: String? +) \ No newline at end of file diff --git a/dongne-common/src/main/kotlin/io/beaniejoy/dongnecafe/security/JwtTokenUtils.kt b/dongne-common/src/main/kotlin/io/beaniejoy/dongnecafe/security/JwtTokenUtils.kt index 69cf1e6..08bb800 100644 --- a/dongne-common/src/main/kotlin/io/beaniejoy/dongnecafe/security/JwtTokenUtils.kt +++ b/dongne-common/src/main/kotlin/io/beaniejoy/dongnecafe/security/JwtTokenUtils.kt @@ -1,11 +1,15 @@ package io.beaniejoy.dongnecafe.security +import io.jsonwebtoken.Claims +import io.jsonwebtoken.ExpiredJwtException import io.jsonwebtoken.Jwts import io.jsonwebtoken.SignatureAlgorithm import io.jsonwebtoken.security.Keys import mu.KLogging import org.springframework.beans.factory.annotation.Value +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken import org.springframework.security.core.Authentication +import org.springframework.security.core.authority.SimpleGrantedAuthority import org.springframework.stereotype.Component import java.security.Key import java.util.* @@ -14,25 +18,56 @@ import java.util.* class JwtTokenUtils( @Value("\${jwt.secret_key}") private val secretKey: String, - @Value("\${jwt.expiration_time}") - private val expirationTime: Long + @Value("\${jwt.validity_time_in_sec}") + private val validityTimeSec: Long ) { private val key: Key = Keys.hmacShaKeyFor(secretKey.toByteArray()) + private val validityTimeMilliSec: Long = validityTimeSec * 1000 - companion object: KLogging() + companion object : KLogging() { + const val AUTHORITIES_KEY = "authorities" + } fun createToken(authentication: Authentication): String { + logger.info { "test = ${authentication.name}" } val authenticatedMember = (authentication.principal as SecurityUser).member + val authorities = authentication.authorities.joinToString(",") { it.authority } + val nowTime = Date().time - val expirationDate = Date(nowTime + this.expirationTime) + val expirationDate = Date(nowTime + this.validityTimeMilliSec) return Jwts.builder() .setSubject(authenticatedMember.email) - .claim("memberId", authenticatedMember.id) - .claim("email", authenticatedMember.email) - .claim("roles", authentication.authorities.joinToString(",") { it.authority }) + .claim(AUTHORITIES_KEY, authorities) .signWith(key, SignatureAlgorithm.HS256) .setExpiration(expirationDate) .compact() } + + fun getAuthentication(accessToken: String): Authentication? { + val claims = getValidTokenBody(accessToken) + ?: return null + + val authorities = claims[AUTHORITIES_KEY].toString().split(",") + .map { SimpleGrantedAuthority(it) } + + return UsernamePasswordAuthenticationToken(claims.subject, accessToken, authorities) + } + + // jwt access token 유효성 검증 및 claims 획득 + private fun getValidTokenBody(accessToken: String): Claims? { + return try { + Jwts.parserBuilder() + .setSigningKey(key) + .build() + .parseClaimsJws(accessToken) + .body + } catch (e: ExpiredJwtException) { + logger.error { "JWT access token expired. > Error: ${e.message}" } + null + } catch (e: Exception) { + logger.error { "JWT access token invalid. > Error: ${e.message}" } + null + } + } } \ No newline at end of file diff --git a/dongne-service-api/src/main/kotlin/io/beaniejoy/dongnecafe/common/config/SecurityConfig.kt b/dongne-service-api/src/main/kotlin/io/beaniejoy/dongnecafe/common/config/SecurityConfig.kt index 9dcf6be..7bf46f1 100644 --- a/dongne-service-api/src/main/kotlin/io/beaniejoy/dongnecafe/common/config/SecurityConfig.kt +++ b/dongne-service-api/src/main/kotlin/io/beaniejoy/dongnecafe/common/config/SecurityConfig.kt @@ -1,8 +1,12 @@ package io.beaniejoy.dongnecafe.common.config +import io.beaniejoy.dongnecafe.security.JwtAuthenticationConfigurer +import io.beaniejoy.dongnecafe.security.JwtTokenUtils +import org.springframework.beans.factory.annotation.Autowired import org.springframework.boot.autoconfigure.security.servlet.PathRequest import org.springframework.context.annotation.Bean import org.springframework.context.annotation.Configuration +import org.springframework.http.HttpMethod import org.springframework.security.config.annotation.web.builders.HttpSecurity import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity import org.springframework.security.config.annotation.web.configuration.WebSecurityCustomizer @@ -11,19 +15,28 @@ import org.springframework.security.web.SecurityFilterChain @Configuration @EnableWebSecurity class SecurityConfig { + @Autowired + lateinit var jwtTokenUtils: JwtTokenUtils + @Bean fun filterChain(http: HttpSecurity): SecurityFilterChain { return http .csrf().disable() - .formLogin().disable() .authorizeRequests() - .anyRequest().authenticated() // 임시 허용 + .anyRequest().authenticated() .and() + .also { jwtAuthenticationConfigurer(it) } .build() } + private fun jwtAuthenticationConfigurer(http: HttpSecurity) { + http + .apply(JwtAuthenticationConfigurer()) + .jwtTokenUtils(jwtTokenUtils) + } + @Bean fun webSecurityCustomizer(): WebSecurityCustomizer { return WebSecurityCustomizer { web -> diff --git a/dongne-service-api/src/main/kotlin/io/beaniejoy/dongnecafe/domain/cafe/service/CafeMenuService.kt b/dongne-service-api/src/main/kotlin/io/beaniejoy/dongnecafe/domain/cafe/service/CafeMenuService.kt index bf40940..72733c6 100644 --- a/dongne-service-api/src/main/kotlin/io/beaniejoy/dongnecafe/domain/cafe/service/CafeMenuService.kt +++ b/dongne-service-api/src/main/kotlin/io/beaniejoy/dongnecafe/domain/cafe/service/CafeMenuService.kt @@ -1,7 +1,7 @@ package io.beaniejoy.dongnecafe.domain.cafe.service import io.beaniejoy.dongnecafe.domain.cafe.model.response.CafeMenuDetailedInfo -import io.beaniejoy.dongnecafe.domain.cafe.error.CafeMenuNotFoundException +import io.beaniejoy.dongnecafe.error.exception.CafeMenuNotFoundException import io.beaniejoy.dongnecafe.domain.cafe.model.request.CafeMenuUpdateRequest import io.beaniejoy.dongnecafe.domain.cafe.repository.CafeMenuRepository import org.springframework.data.repository.findByIdOrNull diff --git a/dongne-service-api/src/main/kotlin/io/beaniejoy/dongnecafe/domain/cafe/service/CafeService.kt b/dongne-service-api/src/main/kotlin/io/beaniejoy/dongnecafe/domain/cafe/service/CafeService.kt index 9452130..e311c5d 100644 --- a/dongne-service-api/src/main/kotlin/io/beaniejoy/dongnecafe/domain/cafe/service/CafeService.kt +++ b/dongne-service-api/src/main/kotlin/io/beaniejoy/dongnecafe/domain/cafe/service/CafeService.kt @@ -4,8 +4,8 @@ import io.beaniejoy.dongnecafe.domain.cafe.model.response.CafeDetailedInfo import io.beaniejoy.dongnecafe.domain.cafe.model.response.CafeSearchInfo import io.beaniejoy.dongnecafe.domain.cafe.model.request.CafeMenuRegisterRequest import io.beaniejoy.dongnecafe.domain.cafe.entity.Cafe -import io.beaniejoy.dongnecafe.domain.cafe.error.CafeExistedException -import io.beaniejoy.dongnecafe.domain.cafe.error.CafeNotFoundException +import io.beaniejoy.dongnecafe.error.exception.CafeExistedException +import io.beaniejoy.dongnecafe.error.exception.CafeNotFoundException import io.beaniejoy.dongnecafe.domain.cafe.repository.CafeRepository import mu.KLogging import org.springframework.data.domain.Page diff --git a/dongne-service-api/src/main/kotlin/io/beaniejoy/dongnecafe/domain/cafe/service/MenuOptionService.kt b/dongne-service-api/src/main/kotlin/io/beaniejoy/dongnecafe/domain/cafe/service/MenuOptionService.kt index 06236d8..a34440e 100644 --- a/dongne-service-api/src/main/kotlin/io/beaniejoy/dongnecafe/domain/cafe/service/MenuOptionService.kt +++ b/dongne-service-api/src/main/kotlin/io/beaniejoy/dongnecafe/domain/cafe/service/MenuOptionService.kt @@ -1,6 +1,6 @@ package io.beaniejoy.dongnecafe.domain.cafe.service -import io.beaniejoy.dongnecafe.domain.cafe.error.MenuOptionNotFoundException +import io.beaniejoy.dongnecafe.error.exception.MenuOptionNotFoundException import io.beaniejoy.dongnecafe.domain.cafe.model.request.MenuOptionUpdateRequest import io.beaniejoy.dongnecafe.domain.cafe.repository.MenuOptionRepository import org.springframework.data.repository.findByIdOrNull diff --git a/dongne-service-api/src/main/kotlin/io/beaniejoy/dongnecafe/domain/cafe/service/OptionDetailService.kt b/dongne-service-api/src/main/kotlin/io/beaniejoy/dongnecafe/domain/cafe/service/OptionDetailService.kt index 4cbe0b7..94e5753 100644 --- a/dongne-service-api/src/main/kotlin/io/beaniejoy/dongnecafe/domain/cafe/service/OptionDetailService.kt +++ b/dongne-service-api/src/main/kotlin/io/beaniejoy/dongnecafe/domain/cafe/service/OptionDetailService.kt @@ -1,6 +1,6 @@ package io.beaniejoy.dongnecafe.domain.cafe.service -import io.beaniejoy.dongnecafe.domain.cafe.error.OptionDetailNotFoundException +import io.beaniejoy.dongnecafe.error.exception.OptionDetailNotFoundException import io.beaniejoy.dongnecafe.domain.cafe.model.request.OptionDetailUpdateRequest import io.beaniejoy.dongnecafe.domain.cafe.repository.OptionDetailRepository import org.springframework.data.repository.findByIdOrNull diff --git a/dongne-service-api/src/main/kotlin/io/beaniejoy/dongnecafe/domain/cafe/error/CafeExceptionHandler.kt b/dongne-service-api/src/main/kotlin/io/beaniejoy/dongnecafe/error/CafeExceptionHandler.kt similarity index 81% rename from dongne-service-api/src/main/kotlin/io/beaniejoy/dongnecafe/domain/cafe/error/CafeExceptionHandler.kt rename to dongne-service-api/src/main/kotlin/io/beaniejoy/dongnecafe/error/CafeExceptionHandler.kt index 7b1f1fd..1d869ea 100644 --- a/dongne-service-api/src/main/kotlin/io/beaniejoy/dongnecafe/domain/cafe/error/CafeExceptionHandler.kt +++ b/dongne-service-api/src/main/kotlin/io/beaniejoy/dongnecafe/error/CafeExceptionHandler.kt @@ -1,5 +1,6 @@ -package io.beaniejoy.dongnecafe.domain.cafe.error +package io.beaniejoy.dongnecafe.error +import io.beaniejoy.dongnecafe.error.exception.CafeNotFoundException import org.springframework.http.ResponseEntity import org.springframework.web.bind.annotation.ExceptionHandler import org.springframework.web.bind.annotation.RestControllerAdvice diff --git a/dongne-service-api/src/main/kotlin/io/beaniejoy/dongnecafe/domain/cafe/error/CafeExistedException.kt b/dongne-service-api/src/main/kotlin/io/beaniejoy/dongnecafe/error/exception/CafeExistedException.kt similarity index 65% rename from dongne-service-api/src/main/kotlin/io/beaniejoy/dongnecafe/domain/cafe/error/CafeExistedException.kt rename to dongne-service-api/src/main/kotlin/io/beaniejoy/dongnecafe/error/exception/CafeExistedException.kt index ac08e0d..e88e84c 100644 --- a/dongne-service-api/src/main/kotlin/io/beaniejoy/dongnecafe/domain/cafe/error/CafeExistedException.kt +++ b/dongne-service-api/src/main/kotlin/io/beaniejoy/dongnecafe/error/exception/CafeExistedException.kt @@ -1,3 +1,3 @@ -package io.beaniejoy.dongnecafe.domain.cafe.error +package io.beaniejoy.dongnecafe.error.exception class CafeExistedException(name: String) : RuntimeException("Cafe[$name] is already existed") \ No newline at end of file diff --git a/dongne-service-api/src/main/kotlin/io/beaniejoy/dongnecafe/domain/cafe/error/CafeMenuNotFoundException.kt b/dongne-service-api/src/main/kotlin/io/beaniejoy/dongnecafe/error/exception/CafeMenuNotFoundException.kt similarity index 76% rename from dongne-service-api/src/main/kotlin/io/beaniejoy/dongnecafe/domain/cafe/error/CafeMenuNotFoundException.kt rename to dongne-service-api/src/main/kotlin/io/beaniejoy/dongnecafe/error/exception/CafeMenuNotFoundException.kt index d569449..bb60691 100644 --- a/dongne-service-api/src/main/kotlin/io/beaniejoy/dongnecafe/domain/cafe/error/CafeMenuNotFoundException.kt +++ b/dongne-service-api/src/main/kotlin/io/beaniejoy/dongnecafe/error/exception/CafeMenuNotFoundException.kt @@ -1,4 +1,4 @@ -package io.beaniejoy.dongnecafe.domain.cafe.error +package io.beaniejoy.dongnecafe.error.exception class CafeMenuNotFoundException(menuId: Long, cafeId: Long) : RuntimeException("Cafe[${cafeId}]의 Menu[${menuId}]는 존재하지 않는 메뉴입니다.") \ No newline at end of file diff --git a/dongne-service-api/src/main/kotlin/io/beaniejoy/dongnecafe/domain/cafe/error/CafeNotFoundException.kt b/dongne-service-api/src/main/kotlin/io/beaniejoy/dongnecafe/error/exception/CafeNotFoundException.kt similarity index 64% rename from dongne-service-api/src/main/kotlin/io/beaniejoy/dongnecafe/domain/cafe/error/CafeNotFoundException.kt rename to dongne-service-api/src/main/kotlin/io/beaniejoy/dongnecafe/error/exception/CafeNotFoundException.kt index 63a183c..e8a0c09 100644 --- a/dongne-service-api/src/main/kotlin/io/beaniejoy/dongnecafe/domain/cafe/error/CafeNotFoundException.kt +++ b/dongne-service-api/src/main/kotlin/io/beaniejoy/dongnecafe/error/exception/CafeNotFoundException.kt @@ -1,3 +1,3 @@ -package io.beaniejoy.dongnecafe.domain.cafe.error +package io.beaniejoy.dongnecafe.error.exception class CafeNotFoundException(cafeId: Long) : RuntimeException("Cafe[$cafeId] is not found") \ No newline at end of file diff --git a/dongne-service-api/src/main/kotlin/io/beaniejoy/dongnecafe/domain/cafe/error/MenuOptionNotFoundException.kt b/dongne-service-api/src/main/kotlin/io/beaniejoy/dongnecafe/error/exception/MenuOptionNotFoundException.kt similarity index 69% rename from dongne-service-api/src/main/kotlin/io/beaniejoy/dongnecafe/domain/cafe/error/MenuOptionNotFoundException.kt rename to dongne-service-api/src/main/kotlin/io/beaniejoy/dongnecafe/error/exception/MenuOptionNotFoundException.kt index 228fd9d..cb42fe7 100644 --- a/dongne-service-api/src/main/kotlin/io/beaniejoy/dongnecafe/domain/cafe/error/MenuOptionNotFoundException.kt +++ b/dongne-service-api/src/main/kotlin/io/beaniejoy/dongnecafe/error/exception/MenuOptionNotFoundException.kt @@ -1,3 +1,3 @@ -package io.beaniejoy.dongnecafe.domain.cafe.error +package io.beaniejoy.dongnecafe.error.exception class MenuOptionNotFoundException(menuOptionId: Long) : RuntimeException("MenuOption[$menuOptionId] is not found") \ No newline at end of file diff --git a/dongne-service-api/src/main/kotlin/io/beaniejoy/dongnecafe/domain/cafe/error/OptionDetailNotFoundException.kt b/dongne-service-api/src/main/kotlin/io/beaniejoy/dongnecafe/error/exception/OptionDetailNotFoundException.kt similarity index 71% rename from dongne-service-api/src/main/kotlin/io/beaniejoy/dongnecafe/domain/cafe/error/OptionDetailNotFoundException.kt rename to dongne-service-api/src/main/kotlin/io/beaniejoy/dongnecafe/error/exception/OptionDetailNotFoundException.kt index 59b5a88..69df3ac 100644 --- a/dongne-service-api/src/main/kotlin/io/beaniejoy/dongnecafe/domain/cafe/error/OptionDetailNotFoundException.kt +++ b/dongne-service-api/src/main/kotlin/io/beaniejoy/dongnecafe/error/exception/OptionDetailNotFoundException.kt @@ -1,3 +1,3 @@ -package io.beaniejoy.dongnecafe.domain.cafe.error +package io.beaniejoy.dongnecafe.error.exception class OptionDetailNotFoundException(optionDetailId: Long) : RuntimeException("OptionDetail[$optionDetailId] is not found") \ No newline at end of file diff --git a/dongne-service-api/src/main/kotlin/io/beaniejoy/dongnecafe/security/JwtAuthenticationConfigurer.kt b/dongne-service-api/src/main/kotlin/io/beaniejoy/dongnecafe/security/JwtAuthenticationConfigurer.kt new file mode 100644 index 0000000..cbaa79a --- /dev/null +++ b/dongne-service-api/src/main/kotlin/io/beaniejoy/dongnecafe/security/JwtAuthenticationConfigurer.kt @@ -0,0 +1,25 @@ +package io.beaniejoy.dongnecafe.security + +import io.beaniejoy.dongnecafe.security.filter.JwtAuthenticationFilter +import org.springframework.security.config.annotation.SecurityConfigurerAdapter +import org.springframework.security.config.annotation.web.builders.HttpSecurity +import org.springframework.security.web.DefaultSecurityFilterChain +import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter + +class JwtAuthenticationConfigurer : + SecurityConfigurerAdapter() { + private var jwtTokenUtils: JwtTokenUtils? = null + + override fun configure(http: HttpSecurity) { + http + .addFilterBefore( + JwtAuthenticationFilter(this.jwtTokenUtils!!), + UsernamePasswordAuthenticationFilter::class.java + ) + } + + fun jwtTokenUtils(jwtTokenUtils: JwtTokenUtils): JwtAuthenticationConfigurer { + this.jwtTokenUtils = jwtTokenUtils + return this + } +} \ No newline at end of file diff --git a/dongne-service-api/src/main/kotlin/io/beaniejoy/dongnecafe/security/filter/JwtAuthenticationFilter.kt b/dongne-service-api/src/main/kotlin/io/beaniejoy/dongnecafe/security/filter/JwtAuthenticationFilter.kt new file mode 100644 index 0000000..8719aec --- /dev/null +++ b/dongne-service-api/src/main/kotlin/io/beaniejoy/dongnecafe/security/filter/JwtAuthenticationFilter.kt @@ -0,0 +1,55 @@ +package io.beaniejoy.dongnecafe.security.filter + +import io.beaniejoy.dongnecafe.security.JwtTokenUtils +import mu.KotlinLogging +import org.springframework.security.core.context.SecurityContextHolder +import org.springframework.web.filter.GenericFilterBean +import javax.servlet.FilterChain +import javax.servlet.ServletRequest +import javax.servlet.ServletResponse +import javax.servlet.http.HttpServletRequest + +class JwtAuthenticationFilter( + private val jwtTokenUtils: JwtTokenUtils +) : GenericFilterBean() { + private val log = KotlinLogging.logger {} + + companion object { + private const val AUTHORIZATION = "Authorization" + private const val BEARER = "Bearer" + private const val WHITESPACE = " " + } + + /** + * JWT access token 인가 처리 + */ + override fun doFilter(request: ServletRequest, response: ServletResponse, chain: FilterChain) { + val httpRequest = request as HttpServletRequest + log.info { "[JwtAuthenticationFilter][${request.dispatcherType}] uri: ${request.requestURI}" } + + getAccessToken(httpRequest)?.let { + jwtTokenUtils.getAuthentication(it) + }?.also { + SecurityContextHolder.getContext().authentication = it + log.info { "Valid Access Token [${it.name}]" } + } + + chain.doFilter(request, response) + } + + private fun getAccessToken(request: HttpServletRequest): String? { + val bearer = request.getHeader(AUTHORIZATION) + ?: return null + + val splitBearer = bearer.split(WHITESPACE) + if (splitBearer.first() != BEARER) { + return null + } + + if (splitBearer.size != 2 || splitBearer.last().isBlank()) { + return null + } + + return splitBearer.last() + } +} \ No newline at end of file diff --git a/dongne-service-api/src/main/resources/application-local.yml b/dongne-service-api/src/main/resources/application-local.yml index 58a0493..eafd9db 100644 --- a/dongne-service-api/src/main/resources/application-local.yml +++ b/dongne-service-api/src/main/resources/application-local.yml @@ -5,4 +5,4 @@ spring: password: beaniejoy # TODO 추후 보안에 대해 생각해보기 jwt: secret_key: aG9wZS15b3UtYWx3YXlzLWJlLWhhcHB5LXRoaXMteWVhcgo= - expiration_time: 86400 \ No newline at end of file + validity_time_in_sec: 86400 \ No newline at end of file diff --git a/dongne-service-api/src/test/kotlin/io/beaniejoy/dongnecafe/domain/cafe/service/CafeMenuServiceTest.kt b/dongne-service-api/src/test/kotlin/io/beaniejoy/dongnecafe/domain/cafe/service/CafeMenuServiceTest.kt index 361267a..f9789a2 100644 --- a/dongne-service-api/src/test/kotlin/io/beaniejoy/dongnecafe/domain/cafe/service/CafeMenuServiceTest.kt +++ b/dongne-service-api/src/test/kotlin/io/beaniejoy/dongnecafe/domain/cafe/service/CafeMenuServiceTest.kt @@ -1,7 +1,7 @@ package io.beaniejoy.dongnecafe.domain.cafe.service import io.beaniejoy.dongnecafe.domain.cafe.entity.CafeMenu -import io.beaniejoy.dongnecafe.domain.cafe.error.CafeMenuNotFoundException +import io.beaniejoy.dongnecafe.error.exception.CafeMenuNotFoundException import io.beaniejoy.dongnecafe.domain.cafe.repository.CafeMenuRepository import io.beaniejoy.dongnecafe.domain.cafe.repository.MenuOptionRepository import io.beaniejoy.dongnecafe.domain.cafe.repository.OptionDetailRepository diff --git a/dongne-service-api/src/test/kotlin/io/beaniejoy/dongnecafe/domain/cafe/service/CafeServiceTest.kt b/dongne-service-api/src/test/kotlin/io/beaniejoy/dongnecafe/domain/cafe/service/CafeServiceTest.kt index 5e5247d..7914fe0 100644 --- a/dongne-service-api/src/test/kotlin/io/beaniejoy/dongnecafe/domain/cafe/service/CafeServiceTest.kt +++ b/dongne-service-api/src/test/kotlin/io/beaniejoy/dongnecafe/domain/cafe/service/CafeServiceTest.kt @@ -1,8 +1,8 @@ package io.beaniejoy.dongnecafe.domain.cafe.service import io.beaniejoy.dongnecafe.domain.cafe.entity.Cafe -import io.beaniejoy.dongnecafe.domain.cafe.error.CafeExistedException -import io.beaniejoy.dongnecafe.domain.cafe.error.CafeNotFoundException +import io.beaniejoy.dongnecafe.error.exception.CafeExistedException +import io.beaniejoy.dongnecafe.error.exception.CafeNotFoundException import io.beaniejoy.dongnecafe.domain.cafe.repository.CafeRepository import io.beaniejoy.dongnecafe.domain.cafe.utils.CafeTestUtils import org.junit.jupiter.api.* diff --git a/dongne-service-api/src/test/resources/application.yml b/dongne-service-api/src/test/resources/application.yml index 71426a6..9619c20 100644 --- a/dongne-service-api/src/test/resources/application.yml +++ b/dongne-service-api/src/test/resources/application.yml @@ -14,4 +14,4 @@ logging: jwt: secret_key: ZG9uZ25lLWNhZmUtcHJvamVjdC1rZXktZm9yLXRlc3QtY29kZQo - expiration_time: 60 \ No newline at end of file + validity_time_in_sec: 60 \ No newline at end of file