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
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package com.back.koreaTravelGuide.common.config.websocket

import com.back.koreaTravelGuide.common.util.JwtUtil
import org.springframework.http.HttpMethod
import org.springframework.http.server.ServerHttpRequest
import org.springframework.http.server.ServerHttpResponse
import org.springframework.stereotype.Component
import org.springframework.web.socket.WebSocketHandler
import org.springframework.web.socket.server.HandshakeInterceptor
import org.springframework.web.util.UriComponentsBuilder
import java.lang.Exception
import java.net.URI

@Component
class JwtHandshakeInterceptor : HandshakeInterceptor {
override fun beforeHandshake(
request: ServerHttpRequest,
response: ServerHttpResponse,
wsHandler: WebSocketHandler,
attributes: MutableMap<String, Any>,
): Boolean {
val uri: URI = request.uri
val method = request.method

// ✅ SockJS 호환을 위한 임시 우회 (브라우저 테스트용)
// - SockJS는 /info 요청을 토큰 없이 보냄
// - 추후 순수 WebSocket 전환 시 제거 예정
if (HttpMethod.OPTIONS == method || uri.path.endsWith("/info")) {
return true
}

val token =
UriComponentsBuilder.fromUri(request.uri)
.build()
.queryParams
.getFirst("token")
?: return false // 토큰 없으면 연결 거부

return if (JwtUtil.validateToken(token)) {
val userId = JwtUtil.getUserIdFromToken(token)
attributes["userId"] = userId
true
} else {
false
}
}

override fun afterHandshake(
request: ServerHttpRequest,
response: ServerHttpResponse,
wsHandler: WebSocketHandler,
exception: Exception?,
) {
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package com.back.koreaTravelGuide.common.config.websocket

import org.springframework.context.annotation.Configuration
import org.springframework.messaging.simp.config.MessageBrokerRegistry
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker
import org.springframework.web.socket.config.annotation.StompEndpointRegistry
import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer

@Configuration
@EnableWebSocketMessageBroker
class WebSocketConfig(
private val jwtHandshakeInterceptor: JwtHandshakeInterceptor,
) : WebSocketMessageBrokerConfigurer {
override fun registerStompEndpoints(registry: StompEndpointRegistry) {
registry.addEndpoint("/ws/chat")
.addInterceptors(JwtHandshakeInterceptor()) // JWT 체크
.setAllowedOrigins("*")
.withSockJS() // 개발 중 호환성
}

override fun configureMessageBroker(registry: MessageBrokerRegistry) {
registry.enableSimpleBroker("/sub") // 구독 경로
registry.setApplicationDestinationPrefixes("/app") // 클라이언트에서 보낼 때
}
}
17 changes: 17 additions & 0 deletions src/main/kotlin/com/back/koreaTravelGuide/common/util/JwtUtil.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.back.koreaTravelGuide.common.util

/*
임시 구현: 테스트 용
토큰이 "test-token"이면 유효하다고 간주
완성 후 이 파일은 삭제 또는 대체
*/
object JwtUtil {
fun validateToken(token: String?): Boolean {
// 테스트용: "test-token"이면 통과
return token != null && token == "test-token"
}

fun getUserIdFromToken(token: String): String {
return "user123" // 테스트용 고정 사용자 ID
}
}