(fix) Umbau zu SCS
### API-Gateway erweitern
- Bestehenden API-Gateway-Service mit zusätzlichen Funktionen ausstatten:
- Rate Limiting implementieren
- Request/Response Logging verbessern
- Cross-Service Tracing mit eindeutigen Request-IDs einführen
This commit is contained in:
parent
834c92dcb2
commit
89e1fa8b52
|
|
@ -1,16 +1,11 @@
|
|||
package at.mocode.gateway.config
|
||||
|
||||
import at.mocode.gateway.config.REQUEST_ID_KEY
|
||||
import at.mocode.gateway.config.REQUEST_START_TIME_KEY
|
||||
import at.mocode.shared.config.AppConfig
|
||||
import io.ktor.http.*
|
||||
import io.ktor.server.application.*
|
||||
import io.ktor.server.plugins.calllogging.*
|
||||
import io.ktor.server.request.*
|
||||
import io.ktor.server.response.*
|
||||
import io.ktor.util.*
|
||||
import org.slf4j.LoggerFactory
|
||||
import org.slf4j.event.Level
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
import java.util.concurrent.Executors
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
|
@ -158,7 +153,7 @@ private fun extractBasePath(path: String): String {
|
|||
if (parts.isEmpty()) return "/"
|
||||
|
||||
// For API paths, include up to the resource name (typically 3 parts: api, version, resource)
|
||||
if (parts.size >= 1 && parts[0] == "api") {
|
||||
if (parts[0] == "api") {
|
||||
val depth = minOf(3, parts.size)
|
||||
return "/" + parts.take(depth).joinToString("/")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,6 @@
|
|||
package at.mocode.gateway.config
|
||||
|
||||
import at.mocode.dto.base.ApiResponse
|
||||
import at.mocode.gateway.config.REQUEST_ID_KEY
|
||||
import at.mocode.gateway.config.REQUEST_START_TIME_KEY
|
||||
import at.mocode.shared.config.AppConfig
|
||||
import io.ktor.http.*
|
||||
import io.ktor.server.application.*
|
||||
|
|
@ -14,9 +12,9 @@ import org.slf4j.event.Level
|
|||
import java.time.LocalDateTime
|
||||
import java.time.format.DateTimeFormatter
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
import java.util.concurrent.atomic.AtomicInteger
|
||||
import java.util.concurrent.Executors
|
||||
import java.util.concurrent.TimeUnit
|
||||
import java.util.concurrent.atomic.AtomicInteger
|
||||
import kotlin.random.Random
|
||||
|
||||
/**
|
||||
|
|
@ -104,7 +102,7 @@ private fun extractBasePath(path: String): String {
|
|||
if (parts.isEmpty()) return "/"
|
||||
|
||||
// For API paths, include up to the resource name (typically 3 parts: api, version, resource)
|
||||
if (parts.size >= 1 && parts[0] == "api") {
|
||||
if (parts[0] == "api") {
|
||||
val depth = minOf(3, parts.size)
|
||||
return "/" + parts.take(depth).joinToString("/")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ private val cacheCleanupScheduler = java.util.Timer("token-cache-cleanup").apply
|
|||
schedule(object : java.util.TimerTask() {
|
||||
override fun run() {
|
||||
if (tokenCache.size > TOKEN_CACHE_MAX_SIZE) {
|
||||
// If cache exceeds max size, remove oldest entries (simple approach)
|
||||
// If the cache exceeds max size, remove the oldest entries (simple approach)
|
||||
val keysToRemove = tokenCache.keys.take(tokenCache.size - TOKEN_CACHE_MAX_SIZE / 2)
|
||||
keysToRemove.forEach { tokenCache.remove(it) }
|
||||
}
|
||||
|
|
@ -56,15 +56,15 @@ private object AdaptiveRateLimiting {
|
|||
|
||||
// Thresholds for CPU usage (percentage)
|
||||
const val CPU_MEDIUM_LOAD_THRESHOLD = 60.0 // Medium load threshold (60%)
|
||||
const val CPU_HIGH_LOAD_THRESHOLD = 80.0 // High load threshold (80%)
|
||||
const val CPU_HIGH_LOAD_THRESHOLD = 80.0 // High-load threshold (80%)
|
||||
|
||||
// Thresholds for memory usage (percentage)
|
||||
const val MEMORY_MEDIUM_LOAD_THRESHOLD = 70.0 // Medium load threshold (70%)
|
||||
const val MEMORY_HIGH_LOAD_THRESHOLD = 85.0 // High load threshold (85%)
|
||||
const val MEMORY_HIGH_LOAD_THRESHOLD = 85.0 // High-load threshold (85%)
|
||||
|
||||
// Rate limit adjustment factors
|
||||
const val MEDIUM_LOAD_FACTOR = 0.7 // Reduce limits to 70% under medium load
|
||||
const val HIGH_LOAD_FACTOR = 0.4 // Reduce limits to 40% under high load
|
||||
const val MEDIUM_LOAD_FACTOR = 0.7 // Reduce limits to 70% under a medium load
|
||||
const val HIGH_LOAD_FACTOR = 0.4 // Reduce limits to 40% under a high load
|
||||
|
||||
// Monitoring interval in milliseconds
|
||||
const val MONITORING_INTERVAL_MS = 5000L // Check every 5 seconds
|
||||
|
|
@ -415,18 +415,18 @@ private fun extractUserIdFromToken(authHeader: String): String? {
|
|||
// Get the user ID
|
||||
val userId = matchResult?.groupValues?.get(1) ?: token.hashCode().toString()
|
||||
|
||||
// Store in cache for future use
|
||||
// Store in a cache for future use
|
||||
tokenCache[tokenHash] = Pair(userId, userType)
|
||||
|
||||
return userId
|
||||
} catch (e: Exception) {
|
||||
} catch (_: Exception) {
|
||||
// If any error occurs during parsing, fall back to using the token hash
|
||||
return authHeader.hashCode().toString()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine user type from JWT token.
|
||||
* Determine a user type from a JWT token.
|
||||
* Parses the JWT token to extract the user role from the claims.
|
||||
* Uses caching to avoid repeated parsing of the same token.
|
||||
*/
|
||||
|
|
@ -467,24 +467,24 @@ private fun determineUserType(authHeader: String): String {
|
|||
val matchResult = subjectRegex.find(payload)
|
||||
val userId = matchResult?.groupValues?.get(1) ?: token.hashCode().toString()
|
||||
|
||||
// Store in cache for future use
|
||||
// Store in a cache for future use
|
||||
tokenCache[tokenHash] = Pair(userId, userType)
|
||||
|
||||
return userType
|
||||
} catch (e: Exception) {
|
||||
} catch (_: Exception) {
|
||||
// If any error occurs during parsing, default to authenticated
|
||||
return "authenticated"
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to determine user type from JWT payload.
|
||||
* Helper function to determine a user type from JWT payload.
|
||||
* Extracted to avoid code duplication between extractUserIdFromToken and determineUserType.
|
||||
*/
|
||||
private fun determineUserTypeFromPayload(payload: String): String {
|
||||
try {
|
||||
// Extract the role using a simple regex
|
||||
// Look for role, roles, or authorities claims
|
||||
// Look for role, roles, or authority claims
|
||||
val roleRegex = "\"(role|roles|authorities)\"\\s*:\\s*\"([^\"]+)\"".toRegex()
|
||||
val matchResult = roleRegex.find(payload)
|
||||
|
||||
|
|
@ -508,9 +508,9 @@ private fun determineUserTypeFromPayload(payload: String): String {
|
|||
}
|
||||
}
|
||||
|
||||
// Default to authenticated if no role information found
|
||||
// Default to authenticate if no role information found
|
||||
return "authenticated"
|
||||
} catch (e: Exception) {
|
||||
} catch (_: Exception) {
|
||||
// If any error occurs during parsing, default to authenticated
|
||||
return "authenticated"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -231,7 +231,7 @@ private fun generateRequestId(): String {
|
|||
val uuid = UUID.randomUUID().toString()
|
||||
val timestamp = System.currentTimeMillis()
|
||||
|
||||
// Get environment prefix safely (first 4 chars or less)
|
||||
// Get environment prefix safely (first 4 chars or fewer)
|
||||
val environment = AppConfig.environment.toString().let { env ->
|
||||
if (env.length > 4) env.substring(0, 4) else env
|
||||
}.lowercase()
|
||||
|
|
|
|||
|
|
@ -1,17 +1,12 @@
|
|||
package at.mocode.gateway
|
||||
|
||||
import at.mocode.gateway.config.configureMonitoring
|
||||
import at.mocode.gateway.config.configureOpenApi
|
||||
import at.mocode.gateway.config.configureRateLimiting
|
||||
import at.mocode.gateway.config.configureRequestTracing
|
||||
import at.mocode.gateway.config.configureSwagger
|
||||
import at.mocode.gateway.config.*
|
||||
import at.mocode.gateway.routing.docRoutes
|
||||
import at.mocode.shared.config.AppConfig
|
||||
import io.ktor.http.*
|
||||
import io.ktor.serialization.kotlinx.json.*
|
||||
import io.ktor.server.application.*
|
||||
import io.ktor.server.http.content.*
|
||||
import io.ktor.server.plugins.calllogging.*
|
||||
import io.ktor.server.plugins.contentnegotiation.*
|
||||
import io.ktor.server.plugins.cors.routing.*
|
||||
import io.ktor.server.response.*
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user