Skip to content
Open

CI #44

Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
9f45100
:bug: fix: [KAN-82] refresh 검증 둜직 λ³€κ²½
RakunKo Jun 1, 2025
dfffbb0
Merge pull request #43 from KEA-ReNov8/KAN-82-CICD
RakunKo Jun 1, 2025
a451386
:bug: fix: [KAN-82] refresh 검증 둜직 λ³€κ²½
RakunKo Jun 1, 2025
831d236
Merge pull request #45 from KEA-ReNov8/KAN-82-CICD
RakunKo Jun 1, 2025
a85174b
:bug: fix: [KAN-82] refresh 검증 둜직 λ³€κ²½
RakunKo Jun 1, 2025
1f506e5
Merge pull request #46 from KEA-ReNov8/KAN-82-CICD
RakunKo Jun 1, 2025
5047ede
:bug: fix: [KAN-82] 토큰 검증 path μΆ”κ°€
RakunKo Jun 2, 2025
1ea1f03
Merge pull request #47 from KEA-ReNov8/KAN-82-CICD
RakunKo Jun 2, 2025
a22b93e
:bug: fix: [KAN-82] cors μ„€μ • μΆ”κ°€
RakunKo Jun 3, 2025
afc3c87
Merge pull request #48 from KEA-ReNov8/KAN-82-CICD
RakunKo Jun 3, 2025
b9273ed
:bug: fix: [KAN-82] 5173 포트 μΆ”κ°€
RakunKo Jun 3, 2025
aa4d76f
Merge pull request #49 from KEA-ReNov8/KAN-82-CICD
RakunKo Jun 3, 2025
1c5c42f
:bug: fix: [KAN-82] refresh 검증 둜직 λ³€κ²½
RakunKo Jun 3, 2025
27d5630
Merge pull request #50 from KEA-ReNov8/KAN-82-CICD
RakunKo Jun 3, 2025
e142363
:bug: fix: [KAN-82] add security setting path
RakunKo Jun 5, 2025
99d17a0
Merge pull request #51 from KEA-ReNov8/KAN-82-CICD
RakunKo Jun 5, 2025
f126763
:bug: fix: [KAN-82] Fix Authentication Path
RakunKo Jun 5, 2025
cb202ae
Merge pull request #52 from KEA-ReNov8/KAN-82-CICD
RakunKo Jun 5, 2025
81cdc89
:bug: fix: [KAN-82] Fix Submodule
RakunKo Jun 5, 2025
23cf669
Merge pull request #53 from KEA-ReNov8/KAN-82-CICD
RakunKo Jun 5, 2025
bad92b2
:bug: fix: [KAN-82] ν™”μ΄νŠΈλ¦¬μŠ€νŠΈ μˆ˜μ •
RakunKo Jun 6, 2025
be42617
Merge pull request #54 from KEA-ReNov8/KAN-82-CICD
RakunKo Jun 6, 2025
06a1bdb
:bug: fix: [KAN-82] ν™”μ΄νŠΈλ¦¬μŠ€νŠΈ μˆ˜μ •
RakunKo Jun 6, 2025
0cecedf
Merge pull request #55 from KEA-ReNov8/KAN-82-CICD
RakunKo Jun 6, 2025
ceebd3f
:bug: fix: [KAN-82] ν™”μ΄νŠΈλ¦¬μŠ€νŠΈ μˆ˜μ •
RakunKo Jun 6, 2025
c379bb0
Merge pull request #56 from KEA-ReNov8/KAN-82-CICD
RakunKo Jun 6, 2025
e7bcca1
:bug: fix: [KAN-82] ν™”μ΄νŠΈλ¦¬μŠ€νŠΈ μˆ˜μ •
RakunKo Jun 8, 2025
4bfe50e
Merge pull request #57 from KEA-ReNov8/KAN-82-CICD
RakunKo Jun 8, 2025
45e2180
:bug: fix: [KAN-82] ν™”μ΄νŠΈλ¦¬μŠ€νŠΈ μˆ˜μ •
RakunKo Jun 8, 2025
ad8385e
Merge pull request #58 from KEA-ReNov8/KAN-82-CICD
RakunKo Jun 8, 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
2 changes: 1 addition & 1 deletion shared-config
64 changes: 43 additions & 21 deletions src/main/kotlin/befly/beflygateway/config/SecurityConfig.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,36 +5,58 @@ import befly.beflygateway.filter.JwtAuthenticationFilter
import befly.beflygateway.handler.OAuth2SuccessHandler
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.http.HttpMethod
import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity
import org.springframework.security.config.web.server.SecurityWebFiltersOrder
import org.springframework.security.config.web.server.ServerHttpSecurity
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter
import org.springframework.security.web.server.SecurityWebFilterChain
import org.springframework.security.web.server.context.NoOpServerSecurityContextRepository

import org.springframework.web.cors.CorsConfiguration
import org.springframework.web.cors.reactive.CorsConfigurationSource
import org.springframework.web.cors.reactive.UrlBasedCorsConfigurationSource

@Configuration
@EnableWebFluxSecurity
class SecurityConfig (
private val oAuth2SuccessHandler: OAuth2SuccessHandler,
private val jwtAuthenticationFilter: JwtAuthenticationFilter
){
private val oAuth2SuccessHandler: OAuth2SuccessHandler,
private val jwtAuthenticationFilter: JwtAuthenticationFilter
) {

@Bean
fun securityWebFilter(http: ServerHttpSecurity): SecurityWebFilterChain =
http.apply {
cors { it.disable() }
csrf { it.disable() }
formLogin { it.disable() }
httpBasic { it.disable() }
exceptionHandling{ it.authenticationEntryPoint(CustomAuthenticationEntryPoint())}
securityContextRepository(NoOpServerSecurityContextRepository.getInstance()) // STATELESS
authorizeExchange {
it.pathMatchers("/oauth2/**", "/login/**", "/auth/refresh").permitAll()
it.pathMatchers("/swagger-ui/**", "/v3/api-docs/**", "/favicon.ico", "/api/docs", "/api/**").permitAll()
it.anyExchange().authenticated()}
oauth2Login{
it.authenticationSuccessHandler(oAuth2SuccessHandler)
}
addFilterAt(jwtAuthenticationFilter, SecurityWebFiltersOrder.AUTHENTICATION)
}.build()
}
http.apply {
cors { it.configurationSource(corsConfigurationSource()) } // βœ… CORS ν™œμ„±ν™”
csrf { it.disable() }
formLogin { it.disable() }
httpBasic { it.disable() }
exceptionHandling { it.authenticationEntryPoint(CustomAuthenticationEntryPoint()) }
securityContextRepository(NoOpServerSecurityContextRepository.getInstance())
authorizeExchange {
it.pathMatchers(
"/oauth2/**", "/login/**", "/auth/refresh", "/auth/signin", "/auth/signup",
"/swagger-ui/**", "/v3/api-docs/**", "/favicon.ico", "/api/docs", "/api/**"
).permitAll()
it.pathMatchers(HttpMethod.GET, "/community/**").permitAll()
it.anyExchange().authenticated()
}
oauth2Login {
it.authenticationSuccessHandler(oAuth2SuccessHandler)
}
addFilterAt(jwtAuthenticationFilter, SecurityWebFiltersOrder.AUTHENTICATION)
}.build()

@Bean
fun corsConfigurationSource(): CorsConfigurationSource {
val config = CorsConfiguration().apply {
allowedOrigins = listOf("https://befly.blog", "http://localhost:5173", "https://befly.blog:5173") //도메인
allowedMethods = listOf("GET", "POST", "PUT", "DELETE", "OPTIONS", "PATCH") // PATCH μΆ”κ°€
allowedHeaders = listOf("*")
allowCredentials = true
}

val source = UrlBasedCorsConfigurationSource()
source.registerCorsConfiguration("/**", config)
return source
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ class JwtAuthenticationFilter(

): WebFilter {
override fun filter(exchange: ServerWebExchange, chain: WebFilterChain): Mono<Void> =
PathWhitelistUtil.isWhitelisted(exchange.request.path.toString())
PathWhitelistUtil.isWhitelisted(exchange.request.method.toString(), exchange.request.path.toString())
.takeIf { it }
?.let {chain.filter(exchange) }
?: run {
Expand All @@ -38,21 +38,11 @@ class JwtAuthenticationFilter(
val userId = jwtProvider.getUserIdFromAccessToken(token)
val auth = getAuthentication(userId.toString())
val context = SecurityContextImpl(auth)
return getAuthorizationToServer(userId)
.flatMap { status ->
if (status) {
val mutatedExchange = exchange.mutate()
.request(exchange.request.mutate().header("X-USER-ID", userId.toString()).build())
.build()
chain.filter(mutatedExchange)
.contextWrite(ReactiveSecurityContextHolder.withSecurityContext(Mono.just(context)))
}
else {
val errorJson = ErrorCode.ACCESS_TOKEN_EXPIRED.toErrorResponse().toJsonBytes()
setErrorResponse(errorJson, exchange.response)
}
}

val mutatedExchange = exchange.mutate()
.request(exchange.request.mutate().header("X-USER-ID", userId.toString()).build())
.build()
chain.filter(mutatedExchange)
.contextWrite(ReactiveSecurityContextHolder.withSecurityContext(Mono.just(context)))
} ?: run {//access 만료 or 잘λͺ»λ¨
jwtProvider.resolveRefreshToken(exchange.request)
?.takeIf { jwtProvider.validateRefreshToken(it) }
Expand All @@ -67,17 +57,6 @@ class JwtAuthenticationFilter(
}
}

private fun getAuthorizationToServer(userId: Long): Mono<Boolean> {
return webClient
.get()
.uri("/auth/exist/user")
.accept(MediaType.ALL)
.header("X-USER-ID", userId.toString())
.retrieve()
.bodyToMono(AuthResponse::class.java)
.map { it.existStatus }
}

private fun getAuthentication(userId: String):Authentication =
UsernamePasswordAuthenticationToken(userId, "", emptyList())

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ class OAuth2SuccessHandler (
): ServerAuthenticationSuccessHandler {
@Value("\${url.front}")
lateinit var FRONT_END_URL: String

//
override fun onAuthenticationSuccess(
webFilterExchange: WebFilterExchange?,
authentication: Authentication?
Expand Down Expand Up @@ -52,7 +52,7 @@ class OAuth2SuccessHandler (
.path("/")
.build()

val refreshCookie = ResponseCookie.from("refreshToken", "${response.refreshToken}!!")
val refreshCookie = ResponseCookie.from("refreshToken", "${response.refreshToken}")
.httpOnly(true)
.secure(true)
.sameSite("Strict")
Expand All @@ -61,13 +61,6 @@ class OAuth2SuccessHandler (
.path("/")
.build()

webClient
.get()
.uri("/auth/refresh")
.accept(MediaType.ALL)
.header("X-Refresh-Token", refreshToken)
.retrieve()

exchange.response.addCookie(accessCookie)
exchange.response.addCookie(refreshCookie)
exchange.response.statusCode = HttpStatus.FOUND
Expand Down
34 changes: 22 additions & 12 deletions src/main/kotlin/befly/beflygateway/utils/PathWhitelistUtil.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,29 @@ import org.springframework.util.AntPathMatcher

object PathWhitelistUtil {
private val matcher = AntPathMatcher()
private val whiteListPatterns = listOf(
"/oauth2/**",
"/login/**",
"/auth/**",
"/swagger-ui/**",
"/v3/api-docs/**",
"/api/docs",
"/api/**",
"/favicon.ico",
"/asdfasdf",
private val whitelistRules: List<Pair<String, String>> = listOf(
"ANY" to "/auth/**",
"ANY" to "/login/**",
"ANY" to "/oauth2/**",
"ANY" to "/swagger-ui/**",
"ANY" to "/v3/api-docs/**",
"ANY" to "/api/**",
"ANY" to "/favicon.ico", // λͺ¨λ“  method ν—ˆμš©ν•  경우
"GET" to "/community/**",
)

fun isWhitelisted(path: String): Boolean {
return whiteListPatterns.any { pattern -> matcher.match(pattern, path) }
fun isWhitelisted(method: String, path: String): Boolean {
val isMatched = whitelistRules.any { (ruleMethod, pattern) ->
(ruleMethod == "ANY" || ruleMethod.equals(method, ignoreCase = true)) &&
matcher.match(pattern, path)
}

// μ˜ˆμ™Έ 경둜 처리: GET /community/notification/** λŠ” μ œμ™Έ
val isExcluded = method.equals("GET", ignoreCase = true) && (
matcher.match("/community/notification/**", path) ||
matcher.match("/community/**/empathy/check", path)
)

return isMatched && !isExcluded
}
}
56 changes: 56 additions & 0 deletions src/main/resources/application-prod.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
spring:
application:
name: befly-gateway-prod

security:
oauth2:
client:
registration:
kakao:
client-id: 732935614e46722be3537af517f72689
client-secret: 5teaK9HRw1Wn1B6oBNx0dkc88Cl5s90H
client-authentication-method: client_secret_post
redirect-uri: https://api.befly.blog/login/oauth2/code/kakao
authorization-grant-type: authorization_code
scope: profile_nickname, profile_image
data:
redis:
host: 34.47.101.253
port: 6379
username: befly
password: befly0443

url:
front: https://befly.blog
back-user: http://user-service.backend.svc.cluster.local
back-community: http://community-service.backend.svc.cluster.local
back-consult: http://consult-service.backend.svc.cluster.local

jwt:
access:
expire: 604800000
secret: dskafndnvkclxzvlkcjxvoqewir329014178923hrjedsbjfajdsnv1238491234jh123
refresh:
prefix: 'refreshToken:'
expire: 604800000
secret: asdfasdfweqriuweru19237489321749791283vbznxcvbwhenyourcasdfasdfasdfqewr
logging:
level:
org.springframework.security: debug

server:
port: 8000

springdoc:
swagger-ui:
enabled: true
path: /api/docs
urls[0]:
name: user-service
url: /api/user-docs
urls[1]:
name: community-service
url: /api/community-docs
urls[2]:
name: consult-service
url: /api/consult-docs