Skip to content

Commit

Permalink
v1.0.2 (#64)
Browse files Browse the repository at this point in the history
* fix: 코틀린 롬복 플러그인 버전 호환성 불일치 문제 해결 및 JWT 토큰 인터페이스 제거 (#60)

* fix: AuthProvider 인터페이스 제거 및 EmotionMapper 추가

* fix: Kotlin 버전이랑 Kotlin-lombok 버전 불일치 해결 및 라이브러리 정리

* fix: M1에서 임베디드 레디스 호환성 문제 해결하기 위해서 로컬에서는 캐시를 사용하지 않도록 하는 방안 (#61)

* fix: throws 테스트 assertj에서 kotest로 변경해서 테스트 진행 (#62)

* fix: throws 테스트 assertj에서 kotest로 변경해서 테스트 진행

* feat: UPDATE README.md

* fix : 감정 중 thrilled 오타 수정 (#63)

Co-authored-by: Seungho Kang <[email protected]>
  • Loading branch information
emiling and seungh0 authored Nov 30, 2021
1 parent cd5d5c2 commit 6ce8c2f
Show file tree
Hide file tree
Showing 23 changed files with 114 additions and 183 deletions.
18 changes: 17 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,19 @@
# dgdg-backend
# BodyMood 백엔드

![Version](https://img.shields.io/github/v/release/depromeet/bodymood-backend?include_prereleases)
[![codecov](https://codecov.io/gh/depromeet/dgdg-backend/branch/develop/graph/badge.svg?token=BBB4PO4JWJ)](https://codecov.io/gh/depromeet/dgdg-backend)

### 프로젝트 설명
Bodymood는 오늘의 운동 루틴과 감정을 한 장의 포스터로 만들어 더욱 재밌고 지속적으로 기록할 수 있게 도와주는 아카이빙 서비스입니다.

### 앱 다운로드
- [AppStore](https://apps.apple.com/kr/app/bodymood/id1588818384)
- [PlayStore](https://play.google.com/store/apps/details?id=com.depromeet.bodymood)

### Language & Framework
- Kotlin, Java
- Spring Boot (Spring Framework, Spring MVC)
- Spring Data JPA (Hibernate) + QueryDSL
- Postgresql, Redis
- Gradle
- Kotest, Mockk
19 changes: 5 additions & 14 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,8 @@ buildscript {
springBootVersion = '2.5.4'
kotlinVersion = '1.5.31'
kotestVersion = '4.4.3'

projectreactorVersion = '1.0.1.RELEASE'

springCloudVersion = '2020.0.4'
kotlinLombokVersion = '1.6.0-RC'
lombokPluginVersion = '6.2.0'
embeddedRedisVersion = "0.7.2"
lombokPluginVersion = '6.1.0'
}
repositories {
maven {
Expand All @@ -22,7 +17,7 @@ buildscript {
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:${kotlinVersion}")
classpath("org.jetbrains.kotlin:kotlin-allopen:${kotlinVersion}")
classpath("org.jetbrains.kotlin:kotlin-noarg:${kotlinVersion}")
classpath("org.jetbrains.kotlin:kotlin-lombok:${kotlinLombokVersion}")
classpath("org.jetbrains.kotlin:kotlin-lombok:${kotlinVersion}")
classpath("io.freefair.gradle:lombok-plugin:${lombokPluginVersion}")
}
}
Expand Down Expand Up @@ -86,16 +81,12 @@ subprojects {
compileOnly'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'

implementation 'org.springframework.boot:spring-boot-starter-webflux'
implementation ("org.projectreactor:reactor-spring:${projectreactorVersion}")

// Redis
implementation("org.springframework.boot:spring-boot-starter-data-redis")
implementation("it.ozimov:embedded-redis:${embeddedRedisVersion}")

// kotest
testImplementation("io.kotest:kotest-runner-junit5:${kotestVersion}")
testImplementation("io.kotest:kotest-extensions-spring:${kotestVersion}")

// mockk
testImplementation("io.mockk:mockk:1.12.0")
}

configurations {
Expand Down
4 changes: 3 additions & 1 deletion dgdg-api/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ dependencies {
// spring web
implementation 'org.springframework.boot:spring-boot-starter-web'

// webflux
implementation 'org.springframework.boot:spring-boot-starter-webflux'

// spring cloud
implementation 'org.springframework.cloud:spring-cloud-starter-openfeign'

Expand All @@ -30,6 +33,5 @@ dependencies {

// Redis
implementation("org.springframework.boot:spring-boot-starter-data-redis")
implementation("it.ozimov:embedded-redis:${embeddedRedisVersion}")
}

Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@ package com.depromeet.dgdg.config.auth

import com.depromeet.dgdg.common.exception.UnAuthorizedException
import com.depromeet.dgdg.domain.domain.user.repository.UserRepository
import com.depromeet.dgdg.provider.token.AuthTokenProvider
import com.depromeet.dgdg.provider.token.dto.AuthTokenPayload
import com.depromeet.dgdg.provider.token.JwtAuthTokenProvider
import org.springframework.http.HttpHeaders
import org.springframework.stereotype.Component
import org.springframework.util.StringUtils
Expand All @@ -14,7 +13,7 @@ import javax.servlet.http.HttpServletResponse

@Component
class AuthInterceptor(
private val tokenProvider: AuthTokenProvider<AuthTokenPayload>,
private val jwtAuthTokenProvider: JwtAuthTokenProvider,
private val userRepository: UserRepository
) : HandlerInterceptor {

Expand All @@ -29,7 +28,7 @@ class AuthInterceptor(
throw UnAuthorizedException("잘못된 토큰입니다. Authorization 헤더가 비었거나 Bearer 타입의 토큰이 아닙니다. header: ($header)")
}
val token = header.split(BEARER_PREFIX)[1]
val payload = tokenProvider.getPayload(token)
val payload = jwtAuthTokenProvider.getPayload(token)

if (!userRepository.existsById(payload.userId)) {
throw UnAuthorizedException("잘못된 토큰(${payload})입니다. 해당하는 유저 (${payload.userId})는 존재하지 않습니다")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import org.springframework.cache.CacheManager
import org.springframework.cache.annotation.CachingConfigurerSupport
import org.springframework.cache.annotation.EnableCaching
import org.springframework.context.annotation.Configuration
import org.springframework.context.annotation.Profile
import org.springframework.data.redis.cache.RedisCacheConfiguration
import org.springframework.data.redis.cache.RedisCacheManager
import org.springframework.data.redis.connection.RedisConnectionFactory
Expand All @@ -13,6 +14,7 @@ import org.springframework.data.redis.serializer.RedisSerializationContext
import org.springframework.data.redis.serializer.StringRedisSerializer
import java.time.Duration

@Profile("local-pg", "dev", "prod")
@EnableCaching
@Configuration
class CacheConfig(
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package com.depromeet.dgdg.controller
import com.depromeet.dgdg.controller.dto.response.BaseResponse
import com.depromeet.dgdg.domain.domain.user.User
import com.depromeet.dgdg.domain.domain.user.repository.UserRepository
import com.depromeet.dgdg.provider.token.AuthTokenProvider
import com.depromeet.dgdg.provider.token.JwtAuthTokenProvider
import com.depromeet.dgdg.provider.token.dto.AuthTokenPayload
import com.depromeet.dgdg.service.auth.dto.response.AuthResponse
import io.swagger.v3.oas.annotations.Operation
Expand All @@ -15,7 +15,7 @@ import org.springframework.web.bind.annotation.RestController
@RestController
class LocalTestController(
private val userRepository: UserRepository,
private val tokenProvider: AuthTokenProvider<AuthTokenPayload>
private val jwtAuthTokenProvider: JwtAuthTokenProvider
) {

@Operation(summary = "[로컬 및 개발용] 테스트용 토큰을 발급 받는 API")
Expand All @@ -25,11 +25,11 @@ class LocalTestController(
?: user
userRepository.save(user)

if (!(user.refreshToken != null && tokenProvider.isValidRefreshToken(user.refreshToken))) {
user.updateRefreshToken(tokenProvider.createRefreshToken())
if (!(user.refreshToken != null && jwtAuthTokenProvider.isValidRefreshToken(user.refreshToken))) {
user.updateRefreshToken(jwtAuthTokenProvider.createRefreshToken())
userRepository.save(user)
}
val accessToken = tokenProvider.createAccessToken(AuthTokenPayload(user.id))
val accessToken = jwtAuthTokenProvider.createAccessToken(AuthTokenPayload(user.id))
return BaseResponse.success(AuthResponse.of(accessToken, user.refreshToken))
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package com.depromeet.dgdg.controller.emotion

import com.depromeet.dgdg.controller.dto.response.BaseResponse
import com.depromeet.dgdg.controller.emotion.dto.response.EmotionResponse
import com.depromeet.dgdg.domain.domain.poster.Emotion
import com.depromeet.dgdg.mapper.emotion.EmotionMapper
import io.swagger.v3.oas.annotations.Operation
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.RestController
Expand All @@ -13,8 +13,7 @@ class EmotionController {
@Operation(summary = "감정 카테고리 종류를 조회하는 API")
@GetMapping("/api/v1/emotions/categories")
fun getEmotions(): BaseResponse<List<EmotionResponse>> {
return BaseResponse.success(Emotion.values()
.map { EmotionResponse.of(it) })
return BaseResponse.success(EmotionMapper.getEmotionCategories())
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.depromeet.dgdg.mapper.emotion

import com.depromeet.dgdg.controller.emotion.dto.response.EmotionResponse
import com.depromeet.dgdg.domain.domain.poster.Emotion

object EmotionMapper {

fun getEmotionCategories(): List<EmotionResponse> {
return Emotion.values()
.map { EmotionResponse.of(it) }
}

}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@ import java.util.*
@Component
class JwtAuthTokenProvider(
val jwtProperties: JwtProperties
) : AuthTokenProvider<AuthTokenPayload> {
) {

override fun createAccessToken(payload: AuthTokenPayload): String {
fun createAccessToken(payload: AuthTokenPayload): String {
try {
val now = Date()
val expiresAt = Date(now.time + jwtProperties.accessTokenExpiresTime)
Expand All @@ -34,7 +34,7 @@ class JwtAuthTokenProvider(
}
}

override fun getPayload(accessToken: String): AuthTokenPayload {
fun getPayload(accessToken: String): AuthTokenPayload {
val verifier = JWT.require(Algorithm.HMAC256(jwtProperties.secret))
.withIssuer(jwtProperties.issuer)
.build()
Expand All @@ -48,7 +48,7 @@ class JwtAuthTokenProvider(
}
}

override fun createRefreshToken(): String {
fun createRefreshToken(): String {
try {
val now = Date()
val expiresAt = Date(now.time + jwtProperties.refreshTokenExpiresTime)
Expand All @@ -64,7 +64,7 @@ class JwtAuthTokenProvider(
}
}

override fun validateRefreshToken(refreshToken: String) {
fun validateRefreshToken(refreshToken: String) {
val verifier = JWT.require(Algorithm.HMAC256(jwtProperties.secret))
.withIssuer(jwtProperties.issuer)
.build()
Expand All @@ -77,7 +77,7 @@ class JwtAuthTokenProvider(
}
}

override fun isValidRefreshToken(refreshToken: String): Boolean {
fun isValidRefreshToken(refreshToken: String): Boolean {
val verifier = JWT.require(Algorithm.HMAC256(jwtProperties.secret))
.withIssuer(jwtProperties.issuer)
.build()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,13 @@ import com.auth0.jwt.JWT
import com.auth0.jwt.JWTVerifier
import com.auth0.jwt.algorithms.Algorithm
import com.auth0.jwt.interfaces.DecodedJWT
import com.depromeet.dgdg.common.ErrorCode
import com.depromeet.dgdg.common.exception.NotFoundException
import com.depromeet.dgdg.service.auth.dto.response.AuthResponse
import com.depromeet.dgdg.domain.domain.user.SocialProvider
import com.depromeet.dgdg.domain.domain.user.User
import com.depromeet.dgdg.domain.domain.user.repository.UserRepository
import com.depromeet.dgdg.external.apple.AppleClient
import com.depromeet.dgdg.external.apple.dto.properties.AppleAuthProperties
import com.depromeet.dgdg.provider.token.AuthTokenProvider
import com.depromeet.dgdg.provider.token.dto.AuthTokenPayload
import com.depromeet.dgdg.provider.token.JwtAuthTokenProvider
import com.depromeet.dgdg.provider.token.dto.AuthTokenPayload.Companion.of
import com.depromeet.dgdg.service.auth.dto.request.AppleAuthHeader
import com.depromeet.dgdg.service.auth.dto.request.AuthRequest
Expand All @@ -32,7 +29,7 @@ import java.util.*
class AppleLoginService(
private val appleLoginValidator: AppleLoginValidator,
private val userRepository: UserRepository,
private val jwtAuthTokenProvider: AuthTokenProvider<AuthTokenPayload>
private val jwtAuthTokenProvider: JwtAuthTokenProvider
) {
fun handleAuthentication(request: AuthRequest) : AuthResponse {
val appleId = appleLoginValidator.getUserIdFromToken(request.accessToken)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package com.depromeet.dgdg.service.auth

import com.depromeet.dgdg.common.exception.UnAuthorizedException
import com.depromeet.dgdg.domain.domain.user.repository.UserRepository
import com.depromeet.dgdg.provider.token.AuthTokenProvider
import com.depromeet.dgdg.provider.token.JwtAuthTokenProvider
import com.depromeet.dgdg.provider.token.dto.AuthTokenPayload
import com.depromeet.dgdg.service.auth.dto.request.RefreshTokenRequest
import com.depromeet.dgdg.service.user.findActiveUserById
Expand All @@ -12,7 +12,7 @@ import org.springframework.transaction.annotation.Transactional
@Service
class AuthService(
private val userRepository: UserRepository,
private val authTokenProvider: AuthTokenProvider<AuthTokenPayload>
private val jwtAuthTokenProvider: JwtAuthTokenProvider
) {

@Transactional
Expand All @@ -23,10 +23,10 @@ class AuthService(

@Transactional(readOnly = true)
fun refreshAccessToken(request: RefreshTokenRequest): String {
authTokenProvider.validateRefreshToken(request.refreshToken)
jwtAuthTokenProvider.validateRefreshToken(request.refreshToken)
val user = userRepository.findByRefreshToken(request.refreshToken)
?: throw UnAuthorizedException("유효하지 않은 Refresh token (${request.refreshToken}) 입니다")
return authTokenProvider.createAccessToken(AuthTokenPayload.of(user.id))
return jwtAuthTokenProvider.createAccessToken(AuthTokenPayload.of(user.id))
}

}
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
package com.depromeet.dgdg.service.auth;

import com.depromeet.dgdg.provider.token.JwtAuthTokenProvider;
import com.depromeet.dgdg.service.auth.dto.response.AuthResponse;
import com.depromeet.dgdg.domain.domain.user.SocialProvider;
import com.depromeet.dgdg.external.kakao.KakaoClient;
import com.depromeet.dgdg.external.kakao.dto.response.KakaoUserResponse;
import com.depromeet.dgdg.provider.token.AuthTokenProvider;
import com.depromeet.dgdg.provider.token.dto.AuthTokenPayload;
import com.depromeet.dgdg.domain.domain.user.User;
import com.depromeet.dgdg.domain.domain.user.repository.UserRepository;
Expand All @@ -19,7 +19,7 @@ public class KakaoLoginService {

private final KakaoClient kakaoClient;
private final UserRepository userRepository;
private final AuthTokenProvider<AuthTokenPayload> jwtAuthTokenProvider;
private final JwtAuthTokenProvider jwtAuthTokenProvider;

@Transactional
public AuthResponse handleAuthentication(AuthRequest request) {
Expand Down
Loading

0 comments on commit 6ce8c2f

Please sign in to comment.