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

Socket: ๐Ÿ”ง Migrating the Socket Module from Java to Kotlin #211

Merged
merged 22 commits into from
Dec 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
0427205
rename: application file java to kotlin
psychology50 Dec 24, 2024
0df958d
chore: convert language from java to kotlin in the socket module
psychology50 Dec 24, 2024
711fba2
fix: change application file to kotlin style
psychology50 Dec 24, 2024
e66295b
fix: move @post-construct method function into the class
psychology50 Dec 24, 2024
2ca073f
feat: add kotlin log util
psychology50 Dec 24, 2024
7f1dc4e
refactor: convert auth_service from java to kotlin
psychology50 Dec 24, 2024
17f6cbc
refactor: convert chat_message_send_service from java to kotlin
psychology50 Dec 24, 2024
3c91db6
refactor: convert stomp-message-util from java to kotlin
psychology50 Dec 24, 2024
c1715fc
refactor: convert last-message-id-save-service from java to kotlin
psychology50 Dec 24, 2024
c6c5425
refactor: convert status-service from java to kotlin
psychology50 Dec 24, 2024
5865e78
refactor: convert chat-message-relay-service from java to kotlin
psychology50 Dec 24, 2024
ae2b097
refactor: convert auth-controller from java to kotlin
psychology50 Dec 24, 2024
184d02e
refactor: convert chat-message-controller from java to kotlin
psychology50 Dec 24, 2024
07ba5da
refactor: convert status-controller from java to kotlin
psychology50 Dec 24, 2024
d2df07e
refactor: convert pre-authorized-spel-parser & aspect from java to koโ€ฆ
psychology50 Dec 25, 2024
c90c020
refactor: convert user-principal from java to kotlin
psychology50 Dec 26, 2024
5deaf5a
fix: principal.expired cannot use(lombok compile time), so convert doโ€ฆ
psychology50 Dec 26, 2024
d57e1c4
fix: add jvm-static annotation at create-method in the stomp-message-โ€ฆ
psychology50 Dec 26, 2024
5c4a44c
rename: add evaluate prameter name
psychology50 Dec 26, 2024
5846464
fix: modify is_authenticated to static method
psychology50 Dec 26, 2024
5fcaf85
chore: modify kotlin compile option cause method parameter data lost
psychology50 Dec 26, 2024
2ad9088
fix: divide evaluate logic from execution logic
psychology50 Dec 26, 2024
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
2 changes: 2 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
buildscript {
repositories {
mavenCentral()
gradlePluginPortal()
}
}

Expand Down Expand Up @@ -30,6 +31,7 @@ subprojects {

repositories {
mavenCentral()
gradlePluginPortal()
}

configurations {
Expand Down
12 changes: 12 additions & 0 deletions pennyway-socket/build.gradle
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile

plugins {
id 'java'
id 'org.jetbrains.kotlin.jvm' version '1.8.21'
id 'org.jetbrains.kotlin.plugin.spring' version '1.8.21'
}

bootJar { enabled = true }
Expand Down Expand Up @@ -32,4 +36,12 @@ dependencies {
implementation group: 'org.openapitools', name: 'jackson-databind-nullable', version: '0.2.6'

implementation 'org.springframework.boot:spring-boot-starter-validation:3.2.3'
}

tasks.withType(KotlinCompile) {
kotlinOptions {
freeCompilerArgs = ['-Xjsr305=strict']
javaParameters = true
jvmTarget = '17'
}
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package kr.co.pennyway;

import jakarta.annotation.PostConstruct
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.runApplication
import java.util.*

@SpringBootApplication
class PennywaySocketApplication {
@PostConstruct
fun setDefaultTimeZone() {
TimeZone.setDefault(TimeZone.getTimeZone("Asia/Seoul"))
}
}

fun main(args: Array<String>) {
runApplication<PennywaySocketApplication>(*args)
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
package kr.co.pennyway.socket.common.aop;

import kr.co.pennyway.socket.common.annotation.PreAuthorize
import kr.co.pennyway.socket.common.exception.PreAuthorizeErrorCode
import kr.co.pennyway.socket.common.exception.PreAuthorizeErrorException
import kr.co.pennyway.socket.common.util.PreAuthorizeSpELParser
import kr.co.pennyway.socket.common.util.logger
import org.aspectj.lang.ProceedingJoinPoint
import org.aspectj.lang.annotation.Around
import org.aspectj.lang.annotation.Aspect
import org.aspectj.lang.reflect.MethodSignature
import org.springframework.context.ApplicationContext
import org.springframework.stereotype.Component
import java.lang.reflect.Method
import java.security.Principal

@Aspect
@Component
class PreAuthorizeAspect(private val applicationContext: ApplicationContext) {
private val log = logger()

/**
* {@link PreAuthorize} ์–ด๋…ธํ…Œ์ด์…˜์ด ๋ถ™์€ ๋ฉ”์„œ๋“œ๋ฅผ ๊ฐ€๋กœ์ฑ„๊ณ  ์ธ์ฆ/์ธ๊ฐ€๋ฅผ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค.
*
* @param joinPoint ๊ฐ€๋กœ์ฑˆ ๋ฉ”์„œ๋“œ์˜ ์‹คํ–‰ ์ง€์ 
* @return ์ธ์ฆ/์ธ๊ฐ€๊ฐ€ ์„ฑ๊ณตํ•˜๋ฉด ์›๋ž˜ ๋ฉ”์„œ๋“œ์˜ ์‹คํ–‰ ๊ฒฐ๊ณผ, ์‹คํŒจํ•˜๋ฉด UnauthorizedResponse
* @throws Throwable ๋ฉ”์„œ๋“œ ์‹คํ–‰ ์ค‘ ๋ฐœ์ƒํ•œ ์˜ˆ์™ธ
*/
@Around("@annotation(kr.co.pennyway.socket.common.annotation.PreAuthorize)")
fun execute(joinPoint: ProceedingJoinPoint): Any = with(joinPoint) {
(signature as? MethodSignature)
?.method
?.let { method -> validateAccess(method, this) }
?: throw IllegalStateException("PreAuthorize๋Š” ๋ฉ”์„œ๋“œ์—๋งŒ ์ ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค")
}

private fun validateAccess(method: Method, joinPoint: ProceedingJoinPoint): Any {
val preAuthorize = method.requireAnnotation<PreAuthorize>()
val principal = joinPoint.args.findPrincipal()

evaluateAccess(
principal = principal,
preAuthorize = preAuthorize,
method = method,
args = joinPoint.args
)

return joinPoint.proceed()
}

private fun evaluateAccess(
principal: Principal?,
preAuthorize: PreAuthorize,
method: Method,
args: Array<Any>
) = PreAuthorizeSpELParser
.evaluate(
expression = preAuthorize.value,
method = method,
args = args,
applicationContext = applicationContext
)
.also { result -> handleEvaluationResult(result, principal) }

private fun handleEvaluationResult(
result: PreAuthorizeSpELParser.EvaluationResult,
principal: Principal?
) = when (result) {
is PreAuthorizeSpELParser.EvaluationResult.Permitted -> Unit
is PreAuthorizeSpELParser.EvaluationResult.Denied.Unauthenticated -> {
log.warn("์ธ์ฆ ์‹คํŒจ: {}", principal)
throw PreAuthorizeErrorException(PreAuthorizeErrorCode.UNAUTHENTICATED)
}

is PreAuthorizeSpELParser.EvaluationResult.Denied.Unauthorized -> {
log.warn("์ธ๊ฐ€ ์‹คํŒจ: {}", principal)
throw PreAuthorizeErrorException(PreAuthorizeErrorCode.FORBIDDEN)
}
}

private companion object {
inline fun <reified T : Annotation> Method.requireAnnotation(): T =
getAnnotation(T::class.java)
?: throw IllegalStateException("Required annotation ${T::class.simpleName} not found")

fun Array<Any>.findPrincipal(): Principal? = asSequence()
.filterIsInstance<Principal>()
.firstOrNull()
}
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package kr.co.pennyway.socket.common.security.authenticate;

import kr.co.pennyway.domain.domains.user.domain.User
import kr.co.pennyway.domain.domains.user.type.Role
import java.security.Principal
import java.time.LocalDateTime

data class UserPrincipal(
val userId: Long,
private var _name: String,
var username: String,
var role: Role,
var isChatNotify: Boolean,
var expiresAt: LocalDateTime,
var deviceId: String,
var deviceName: String
) : Principal {
fun isAuthenticated(): Boolean = !isExpired()

fun updateExpiresAt(newExpiresAt: LocalDateTime) {
this.expiresAt = newExpiresAt
}

override fun getName(): String = userId.toString()

fun getDefaultName(): String = _name

private fun isExpired(): Boolean = LocalDateTime.now().isAfter(expiresAt)

companion object {
@JvmStatic
fun of(
user: User,
expiresAt: LocalDateTime,
deviceId: String,
deviceName: String
): UserPrincipal = UserPrincipal(
userId = user.id,
_name = user.name,
username = user.username,
role = user.role,
isChatNotify = user.notifySetting.isChatNotify,
expiresAt = expiresAt,
deviceId = deviceId,
deviceName = deviceName
)
}
}
Loading
Loading