Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[YS-65] feat: 테스트용 토큰 강제 발급 API & AccessToken 갱신 API 구현 #16

Merged
merged 37 commits into from
Jan 3, 2025
Merged
Show file tree
Hide file tree
Changes from 24 commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
ee8b4ec
style: add line for EOF
Ji-soo708 Jan 1, 2025
3560fb0
chore: update springdoc version
Ji-soo708 Jan 1, 2025
871ad82
feat: add generateTestTokenForTestMember method for test
Ji-soo708 Jan 1, 2025
225f15b
feat: add UseCase interface
Ji-soo708 Jan 1, 2025
c83fe2f
feat: add GenerateTestToken api for test member
Ji-soo708 Jan 1, 2025
e66f71f
test: change memberId type from String to Long in test code
Ji-soo708 Jan 1, 2025
ec088d0
chore: add mock dependency for test
Ji-soo708 Jan 1, 2025
e915406
test: add GenerateTestToken test code
Ji-soo708 Jan 1, 2025
2f42a22
test: refactor JwtTokenProviderTest to use Kotest style
Ji-soo708 Jan 1, 2025
5ae21ef
style: rename dto name
Ji-soo708 Jan 1, 2025
8bfa21a
feat: add @ComponentScan to include UseCase beans in application context
Ji-soo708 Jan 1, 2025
2387360
refact: refactor TokenProvider code
Ji-soo708 Jan 2, 2025
ef72cda
feat: add dto for SignIn logic
Ji-soo708 Jan 2, 2025
63d0863
feat: add GenerateTokenWithRefreshToken
Ji-soo708 Jan 2, 2025
83b41c1
test: add GenerateTokenWithRefreshToken test code
Ji-soo708 Jan 2, 2025
da69998
refact: rename entity
Ji-soo708 Jan 2, 2025
65ffa0c
refact: refactor member domain
Ji-soo708 Jan 2, 2025
6387bdb
test: fix test due to changed domain
Ji-soo708 Jan 2, 2025
c08fad6
feat: add MemberGateway
Ji-soo708 Jan 2, 2025
c207cf8
feat: add GetMemberById usecase
Ji-soo708 Jan 2, 2025
065c00b
refact: update MemberRefreshToken response
Ji-soo708 Jan 2, 2025
6db0c19
style: add line for eof
Ji-soo708 Jan 2, 2025
9abb0c3
Merge branch 'dev' into feature/YS-65
Ji-soo708 Jan 2, 2025
6a48fbf
style: update role example
Ji-soo708 Jan 2, 2025
eb68e03
[YS-31] feat: 구글 OAuth 로그인 구현 (#13)
chock-cho Jan 3, 2025
36a0d1c
feat: add GenerateTestToken api for test member
Ji-soo708 Jan 1, 2025
e26fdbf
test: refactor JwtTokenProviderTest to use Kotest style
Ji-soo708 Jan 1, 2025
f5c8cab
feat: add @ComponentScan to include UseCase beans in application context
Ji-soo708 Jan 1, 2025
170352d
feat: add GenerateTokenWithRefreshToken
Ji-soo708 Jan 2, 2025
0f6b999
refact: rename entity
Ji-soo708 Jan 2, 2025
aae3d23
test: fix test due to changed domain
Ji-soo708 Jan 2, 2025
a333982
refact: update MemberRefreshToken response
Ji-soo708 Jan 2, 2025
93550d8
fix: fix conflicts for merge
Ji-soo708 Jan 3, 2025
8538d2c
refact: move usecase file to application
Ji-soo708 Jan 3, 2025
edca1e9
refact: refactor OAuthLoginResponse response structure
Ji-soo708 Jan 3, 2025
7df78cd
fix: fix conflicts for merge
Ji-soo708 Jan 3, 2025
fedb6de
fix: fix conflicts for merge
Ji-soo708 Jan 3, 2025
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: 3 additions & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,8 @@ dependencies {
implementation("org.springframework.boot:spring-boot-starter-security")
implementation("com.github.f4b6a3:ulid-creator:5.2.3")
implementation("org.mariadb.jdbc:mariadb-java-client:2.7.3")
implementation("org.springdoc:springdoc-openapi-starter-webmvc-ui:2.7.0")
implementation ("io.awspring.cloud:spring-cloud-starter-aws:2.4.4")
implementation("org.springdoc:springdoc-openapi-starter-webmvc-ui:2.5.0")
compileOnly("org.projectlombok:lombok")
runtimeOnly("com.mysql:mysql-connector-j")
runtimeOnly("com.h2database:h2")
Expand All @@ -61,6 +61,8 @@ dependencies {
testImplementation("io.kotest:kotest-assertions-core:$koTestVersion")
testImplementation("io.kotest:kotest-property:$koTestVersion")
testImplementation("io.kotest.extensions:kotest-extensions-spring:1.1.2")

testImplementation("io.mockk:mockk:1.13.10")
}

kotlin {
Expand Down
10 changes: 10 additions & 0 deletions src/main/kotlin/com/dobby/backend/DobbyBackendApplication.kt
Original file line number Diff line number Diff line change
@@ -1,8 +1,18 @@
package com.dobby.backend


import com.dobby.backend.domain.usecase.UseCase
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.runApplication
import org.springframework.context.annotation.ComponentScan
import org.springframework.context.annotation.FilterType

@ComponentScan(
includeFilters = [ComponentScan.Filter(
type = FilterType.ASSIGNABLE_TYPE,
classes = [UseCase::class]
)]
)
@SpringBootApplication
class DobbyBackendApplication

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.dobby.backend.domain.gateway

import com.dobby.backend.domain.model.Member

interface MemberGateway {
fun getById(memberId: Long): Member
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
package com.dobby.backend.domain.gateway

import com.dobby.backend.domain.model.Member

interface TokenGateway {
fun generateAccessToken(member: Member): String
fun generateRefreshToken(member: Member): String
fun generateAccessToken(memberId: Long): String
fun generateRefreshToken(memberId: Long): String
fun extractMemberIdFromRefreshToken(token: String): String
}
31 changes: 25 additions & 6 deletions src/main/kotlin/com/dobby/backend/domain/model/Member.kt
Original file line number Diff line number Diff line change
@@ -1,21 +1,40 @@
package com.dobby.backend.domain.model

import com.dobby.backend.util.generateULID
import com.dobby.backend.infrastructure.database.entity.enum.MemberStatus
import com.dobby.backend.infrastructure.database.entity.enum.ProviderType
import com.dobby.backend.infrastructure.database.entity.enum.RoleType
import java.time.LocalDate

data class Member(
val memberId: String,
val memberId: Long,
val name: String,
val email: String,
val oauthEmail: String,
val contactEmail: String,
val provider: ProviderType,
val status: MemberStatus,
val role: RoleType,
val birthDate: LocalDate,
) {

companion object {
fun newMember(
memberId: Long,
name: String,
email: String,
oauthEmail: String,
contactEmail: String,
provider: ProviderType,
status: MemberStatus,
role: RoleType,
birthDate: LocalDate,
) = Member(
memberId = generateULID(),
memberId = memberId,
name = name,
email = email,
oauthEmail = oauthEmail,
contactEmail = contactEmail,
provider = provider,
status = status,
role = role,
birthDate = birthDate,
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package com.dobby.backend.domain.usecase

import com.dobby.backend.domain.gateway.TokenGateway

class GenerateTestToken(
private val tokenGateway: TokenGateway
) : UseCase<GenerateTestToken.Input, GenerateTestToken.Output> {
data class Input(
val memberId: Long
)

data class Output(
val accessToken: String,
val refreshToken: String,
)

override fun execute(input: Input): Output {
val memberId = input.memberId
return Output(
accessToken = tokenGateway.generateAccessToken(memberId),
refreshToken = tokenGateway.generateRefreshToken(memberId)
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package com.dobby.backend.domain.usecase

import com.dobby.backend.domain.gateway.TokenGateway

class GenerateTokenWithRefreshToken(
private val tokenGateway: TokenGateway
) : UseCase<GenerateTokenWithRefreshToken.Input, GenerateTokenWithRefreshToken.Output> {
data class Input(
val refreshToken: String,
)

data class Output(
val accessToken: String,
val refreshToken: String,
val memberId: Long
)

override fun execute(input: Input): Output {
val memberId = tokenGateway.extractMemberIdFromRefreshToken(input.refreshToken).toLong()
return Output(
accessToken = tokenGateway.generateAccessToken(memberId),
refreshToken = tokenGateway.generateRefreshToken(memberId),
memberId = memberId
)
}
}
16 changes: 16 additions & 0 deletions src/main/kotlin/com/dobby/backend/domain/usecase/GetMemberById.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.dobby.backend.domain.usecase

import com.dobby.backend.domain.gateway.MemberGateway
import com.dobby.backend.domain.model.Member

class GetMemberById(
private val memberGateway: MemberGateway,
) : UseCase<GetMemberById.Input, Member> {
data class Input(
val memberId: Long,
)

override fun execute(input: Input): Member {
return memberGateway.getById(input.memberId)
}
}
5 changes: 5 additions & 0 deletions src/main/kotlin/com/dobby/backend/domain/usecase/UseCase.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package com.dobby.backend.domain.usecase

fun interface UseCase<I, O> {
fun execute(input: I): O
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.dobby.backend.infrastructure.database.entity

import AuditingEntity
import com.dobby.backend.domain.model.Member
import com.dobby.backend.infrastructure.database.entity.enum.MemberStatus
import com.dobby.backend.infrastructure.database.entity.enum.ProviderType
import com.dobby.backend.infrastructure.database.entity.enum.RoleType
Expand All @@ -10,7 +11,7 @@ import java.time.LocalDate
@Entity(name = "member")
@Inheritance(strategy = InheritanceType.JOINED)
@DiscriminatorColumn(name = "role_type")
open class Member (
class MemberEntity (
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

로직을 구현하면서 알았는데 Entity와 model을 한 클래스에서 불러와 구현해야 하는 경우가 있어, 이름으로 구분을 주기 위해 다시 Entity를 뒤에 붙였습니다!

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

저도 이 부분이 우려되어서 초반에 네이밍을 달리했었던 기억이 납니다!
좋은 변화라고 생각합니다☺️

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
Expand Down Expand Up @@ -39,4 +40,30 @@ open class Member (

@Column(name = "birth_date", nullable = false)
val birthDate : LocalDate,
) : AuditingEntity()
) : AuditingEntity() {
fun toDomain() = Member(
memberId = id,
name = name,
oauthEmail = oauthEmail,
contactEmail = contactEmail,
provider = provider,
status = status,
role = role,
birthDate = birthDate
)

companion object {
fun fromDomain(member: Member) = with(member) {
MemberEntity(
id = memberId,
name = name,
oauthEmail = oauthEmail,
contactEmail = contactEmail,
provider = provider,
status = status,
role = role,
birthDate = birthDate
)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import java.time.LocalDate

@Entity(name = "participant")
@DiscriminatorValue("PARTICIPANT")
class Participant (
class ParticipantEntity (
@Column(name = "gender", nullable = false)
@Enumerated(EnumType.STRING)
val gender: GenderType,
Expand Down Expand Up @@ -46,7 +46,7 @@ class Participant (
contactEmail: String,
name: String,
birthDate: LocalDate
) : Member(
) : MemberEntity(
id= id,
oauthEmail = oauthEmail,
provider = provider,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import java.time.LocalDate

@Entity(name = "researcher")
@DiscriminatorValue("RESEARCHER")
class Researcher (
class ResearcherEntity (
@Column(name = "univ_email", length = 100, nullable = false)
val univEmail : String,

Expand All @@ -31,7 +31,7 @@ class Researcher (
contactEmail: String,
name: String,
birthDate: LocalDate
) : Member(
) : MemberEntity(
id= id,
oauthEmail = oauthEmail,
provider = provider,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,4 @@ abstract class AuditingEntity {
@LastModifiedDate
@Column(name = "updated_at", nullable = false)
lateinit var updatedAt: LocalDateTime
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@ package com.dobby.backend.infrastructure.database.entity.enum

enum class ProviderType {
NAVER, GOOGLE
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@ package com.dobby.backend.infrastructure.database.entity.enum

enum class RoleType {
RESEARCHER, PARTICIPANT
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.dobby.backend.infrastructure.database.repository

import com.dobby.backend.infrastructure.database.entity.MemberEntity
import org.springframework.data.jpa.repository.JpaRepository

interface MemberJpaRepository : JpaRepository<MemberEntity, Long> {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package com.dobby.backend.infrastructure.gateway

import com.dobby.backend.domain.gateway.MemberGateway
import com.dobby.backend.domain.model.Member
import com.dobby.backend.infrastructure.database.entity.MemberEntity
import com.dobby.backend.infrastructure.database.repository.MemberJpaRepository
import org.springframework.stereotype.Component

@Component
class MemberGatewayImpl(
private val jpaMemberRepository: MemberJpaRepository,
) : MemberGateway {
override fun getById(memberId: Long): Member {
return jpaMemberRepository
.getReferenceById(memberId)
.let(MemberEntity::toDomain)
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package com.dobby.backend.infrastructure.gateway

import com.dobby.backend.domain.gateway.TokenGateway
import com.dobby.backend.domain.model.Member
import com.dobby.backend.infrastructure.token.JwtTokenProvider
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken
import org.springframework.stereotype.Component
Expand All @@ -10,17 +9,17 @@ import org.springframework.stereotype.Component
class TokenGatewayImpl(
private val tokenProvider: JwtTokenProvider,
) : TokenGateway {
override fun generateAccessToken(member: Member): String {
override fun generateAccessToken(memberId: Long): String {
val authentication = UsernamePasswordAuthenticationToken(
member.memberId,
memberId,
null,
)
return tokenProvider.generateAccessToken(authentication)
}

override fun generateRefreshToken(member: Member): String {
override fun generateRefreshToken(memberId: Long): String {
val authentication = UsernamePasswordAuthenticationToken(
member.memberId,
memberId,
null,
)
return tokenProvider.generateRefreshToken(authentication)
Expand Down
Loading
Loading