Skip to content

Commit

Permalink
Add files via upload
Browse files Browse the repository at this point in the history
  • Loading branch information
dreamstar-enterprises authored Aug 11, 2024
1 parent 9a1935f commit e7dd69d
Show file tree
Hide file tree
Showing 7 changed files with 234 additions and 5 deletions.
23 changes: 23 additions & 0 deletions Spring BFF/bff/auth/sessions/CustomSessionIdGenerator.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package com.example.bff.auth.sessions

import org.springframework.session.SessionIdGenerator

/**********************************************************************************************************************/
/**************************************************** SESSION ID GENERATOR ********************************************/
/**********************************************************************************************************************/

// more here:
// https://docs.spring.io/spring-session/reference/configuration/common.html#changing-how-session-ids-are-generated

internal class CustomSessionIdGenerator : SessionIdGenerator {

override fun generate(): String {
// use a UUID with a custom prefix or other unique generation logic
return "BFF-${java.util.UUID.randomUUID()}"
}

}

/**********************************************************************************************************************/
/**************************************************** END OF KOTLIN ***************************************************/
/**********************************************************************************************************************/
10 changes: 7 additions & 3 deletions Spring BFF/bff/auth/sessions/RedisSessionCleanUpConfig.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package com.example.bff.auth.redis

import com.example.bff.props.SpringDataProperties
import com.example.bff.props.SpringSessionProperties
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.data.domain.Range
Expand All @@ -19,10 +21,12 @@ import java.time.Instant
/**********************************************************************************************************************/

// more here:
// https://docs.spring.io/spring-session/reference/configuration/reactive-redis-indexed.html
// https://docs.spring.io/spring-session/reference/configuration/reactive-redis-indexed.html#how-spring-session-cleans-up-expired-sessions

@Configuration
internal class RedisCleanUpConfig {
internal class RedisCleanUpConfig (
private val springSessionProperties: SpringSessionProperties,
){

@Bean
// configuring Redis to Send Keyspace Events
Expand All @@ -35,7 +39,7 @@ internal class RedisCleanUpConfig {
fun reactiveSessionRepositoryCustomizer(): ReactiveSessionRepositoryCustomizer<ReactiveRedisIndexedSessionRepository> {
return ReactiveSessionRepositoryCustomizer { sessionRepository: ReactiveRedisIndexedSessionRepository ->
sessionRepository.setCleanupInterval(
Duration.ofSeconds(30)
springSessionProperties.redis?.sessionCleanUpFrequency?.let { Duration.ofSeconds(it) }
)
}
}
Expand Down
71 changes: 71 additions & 0 deletions Spring BFF/bff/auth/sessions/RedisSessionMapperConfig.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
package com.example.bff.auth.sessions

import com.example.bff.props.SpringSessionProperties
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.data.redis.core.ReactiveRedisOperations
import org.springframework.session.MapSession
import org.springframework.session.config.ReactiveSessionRepositoryCustomizer
import org.springframework.session.data.redis.ReactiveRedisIndexedSessionRepository
import org.springframework.session.data.redis.RedisSessionMapper
import reactor.core.publisher.Mono
import java.util.function.BiFunction

/**********************************************************************************************************************/
/************************************************ REDIS CONFIGURATION *************************************************/
/**********************************************************************************************************************/

// more here:
// https://docs.spring.io/spring-session/reference/configuration/redis.html#configuring-redis-session-mapper

@Configuration
internal class RedisSessionMapperConfig() {

/**
* Customizes the ReactiveRedisIndexedSessionRepository to use the SafeSessionMapper.
*/
@Bean
fun redisSessionRepositoryCustomizer(): ReactiveSessionRepositoryCustomizer<ReactiveRedisIndexedSessionRepository> {
return ReactiveSessionRepositoryCustomizer { redisSessionRepository ->
redisSessionRepository.setRedisSessionMapper(
SafeRedisSessionMapper(
redisSessionRepository.sessionRedisOperations
)
)
}
}

/**
* Implementation of SafeSessionMapper.
*/
internal class SafeRedisSessionMapper(
private var redisOperations: ReactiveRedisOperations<String, Any>
) : BiFunction<String, Map<String, Any>, Mono<MapSession>>{

private val redisProperties = SpringSessionProperties()
private val delegate = RedisSessionMapper()

/**
* Custom session mapper that delegates to the default RedisSessionMapper.
* If an exception occurs, the session is deleted from Redis.
*/
override fun apply(sessionId: String, map: Map<String, Any>): Mono<MapSession> {
return Mono.defer {
try {
// attempt to apply the session mapping
Mono.just(delegate.apply(sessionId, map))
} catch (ex: IllegalStateException) {
// handle exception: delete session from Redis and return empty Mono
redisOperations.delete("${redisProperties.redis?.namespace}:$sessionId")
.then(Mono.empty<MapSession>())
}
}
}

}

}

/**********************************************************************************************************************/
/**************************************************** END OF KOTLIN ***************************************************/
/**********************************************************************************************************************/
21 changes: 21 additions & 0 deletions Spring BFF/bff/auth/sessions/SessionApplicationListener.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package com.example.bff.auth.sessions

import com.example.bff.auth.redis.RedisConnectionFactoryConfig
import org.springframework.session.web.context.AbstractHttpSessionApplicationInitializer
import org.springframework.stereotype.Component

/**********************************************************************************************************************/
/************************************************ REDIS CONFIGURATION *************************************************/
/**********************************************************************************************************************/

// more here:
// https://docs.spring.io/spring-session/reference/http-session.html#httpsession-redis-jc
// https://docs.spring.io/spring-session/reference/http-session.html#_servlet_container_initialization_2

@Component
internal class SessionApplicationInitialiser
: AbstractHttpSessionApplicationInitializer(RedisConnectionFactoryConfig::class.java)

/**********************************************************************************************************************/
/**************************************************** END OF KOTLIN ***************************************************/
/**********************************************************************************************************************/
51 changes: 51 additions & 0 deletions Spring BFF/bff/auth/sessions/SessionListenerConfig.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package com.example.bff.auth.sessions

import org.springframework.context.event.EventListener
import org.springframework.session.events.SessionCreatedEvent
import org.springframework.session.events.SessionDeletedEvent
import org.springframework.session.events.SessionExpiredEvent
import org.springframework.stereotype.Component
import reactor.core.publisher.Mono

/**********************************************************************************************************************/
/************************************************** SESSION CONFIGURATION *********************************************/
/**********************************************************************************************************************/

// more here:
// https://docs.spring.io/spring-session/reference/configuration/reactive-redis-indexed.html#listening-session-events

@Component
// session event listener
internal class SessionListenerConfig {

@EventListener
fun processSessionCreatedEvent(event: SessionCreatedEvent): Mono<Void> {
return Mono.fromRunnable {
// Log or print information about the created session
println("Session created: ${event.sessionId}")
// Your logic for session created event
}
}

@EventListener
fun processSessionDeletedEvent(event: SessionDeletedEvent): Mono<Void> {
return Mono.fromRunnable {
// Log or print information about the deleted session
println("Session deleted: ${event.sessionId}")
// Your logic for session deleted event
}
}

@EventListener
fun processSessionExpiredEvent(event: SessionExpiredEvent): Mono<Void> {
return Mono.fromRunnable {
// Log or print information about the expired session
println("Session expired: ${event.sessionId}")
// Your logic for session expired event
}
}
}

/**********************************************************************************************************************/
/**************************************************** END OF KOTLIN ***************************************************/
/**********************************************************************************************************************/
58 changes: 58 additions & 0 deletions Spring BFF/bff/auth/sessions/SessionService.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package com.example.bff.auth.sessions

import org.springframework.session.FindByIndexNameSessionRepository
import org.springframework.session.ReactiveFindByIndexNameSessionRepository
import org.springframework.session.Session
import org.springframework.session.data.redis.ReactiveRedisIndexedSessionRepository
import org.springframework.session.data.redis.ReactiveRedisIndexedSessionRepository.RedisSession
import org.springframework.stereotype.Service
import reactor.core.publisher.Flux
import reactor.core.publisher.Mono
import java.security.Principal

/**********************************************************************************************************************/
/************************************************ SESSION CONFIGURATION ***********************************************/
/**********************************************************************************************************************/

// more here:
// https://docs.spring.io/spring-session/reference/configuration/redis.html#finding-all-user-sessions

@Service
internal class SessionService(
private val sessions: ReactiveFindByIndexNameSessionRepository<RedisSession>,
private val redisIndexedSessionRepository: ReactiveRedisIndexedSessionRepository
) {

/**
* Retrieves all sessions for a specific user.
* @param principal the principal whose sessions need to be retrieved
* @return a Flux of sessions for the specified user
*/
fun getSessions(principal: Principal): Flux<Session> {
return sessions.findByPrincipalName(principal.name)
.flatMapMany { sessionsMap ->
Flux.fromIterable(sessionsMap.values)
}
}

/**
* Removes a specific session for a user.
* @param principal the principal whose session needs to be removed
* @param sessionIdToDelete the ID of the session to be removed
* @return a Mono indicating completion or error
*/
fun removeSession(principal: Principal, sessionIdToDelete: String): Mono<Void> {
return sessions.findByPrincipalName(principal.name)
.flatMap { userSessions ->
if (userSessions.containsKey(sessionIdToDelete)) {
redisIndexedSessionRepository.deleteById(sessionIdToDelete)
} else {
Mono.empty()
}
}
}
}

/**********************************************************************************************************************/
/**************************************************** END OF KOTLIN ***************************************************/
/**********************************************************************************************************************/
5 changes: 3 additions & 2 deletions Spring BFF/bff/auth/sessions/WebSessionStoreConfig.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package com.example.bff.auth.sessions
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.session.data.redis.ReactiveRedisIndexedSessionRepository
import org.springframework.session.data.redis.ReactiveRedisIndexedSessionRepository.RedisSession
import org.springframework.session.web.server.session.SpringSessionWebSessionStore
import org.springframework.web.server.session.CookieWebSessionIdResolver
import org.springframework.web.server.session.DefaultWebSessionManager
Expand Down Expand Up @@ -36,14 +37,14 @@ internal class WebSessionStoreConfig {
@Bean(name = ["webSessionStore"])
fun webSessionStore(
reactiveRedisIndexedSessionRepository: ReactiveRedisIndexedSessionRepository
): SpringSessionWebSessionStore<ReactiveRedisIndexedSessionRepository.RedisSession> {
): SpringSessionWebSessionStore<RedisSession> {
return SpringSessionWebSessionStore(reactiveRedisIndexedSessionRepository)
}

@Bean(name = ["webSessionManager"])
fun webSessionManager(
cookieWebSessionIdResolver: CookieWebSessionIdResolver,
webSessionStore: SpringSessionWebSessionStore<ReactiveRedisIndexedSessionRepository.RedisSession>
webSessionStore: SpringSessionWebSessionStore<RedisSession>
): WebSessionManager {
val sessionManager = DefaultWebSessionManager()
sessionManager.sessionStore = webSessionStore
Expand Down

0 comments on commit e7dd69d

Please sign in to comment.