From d380c6b8a53c237917d387d8a8b6bacfa6e0cd3d Mon Sep 17 00:00:00 2001 From: guqing Date: Mon, 22 Apr 2024 11:44:46 +0800 Subject: [PATCH] refactor: use spring session 3.3 to adapt --- ...emoryReactiveIndexedSessionRepository.java | 66 ++++++++++++---- ...ctiveFindByIndexNameSessionRepository.java | 24 ------ .../ReactiveIndexedSessionRepository.java | 1 + .../session/SessionInvalidationListener.java | 1 + ...yReactiveIndexedSessionRepositoryTest.java | 78 ++++++++++++++++++- ...eFindByIndexNameSessionRepositoryTest.java | 15 ---- 6 files changed, 128 insertions(+), 57 deletions(-) delete mode 100644 application/src/main/java/run/halo/app/security/session/ReactiveFindByIndexNameSessionRepository.java delete mode 100644 application/src/test/java/run/halo/app/security/session/ReactiveFindByIndexNameSessionRepositoryTest.java diff --git a/application/src/main/java/run/halo/app/security/session/InMemoryReactiveIndexedSessionRepository.java b/application/src/main/java/run/halo/app/security/session/InMemoryReactiveIndexedSessionRepository.java index 1236aa07a6..ee02611594 100644 --- a/application/src/main/java/run/halo/app/security/session/InMemoryReactiveIndexedSessionRepository.java +++ b/application/src/main/java/run/halo/app/security/session/InMemoryReactiveIndexedSessionRepository.java @@ -18,7 +18,7 @@ public class InMemoryReactiveIndexedSessionRepository extends ReactiveMapSession implements ReactiveIndexedSessionRepository, DisposableBean { final IndexResolver indexResolver = - new DelegatingIndexResolver<>(new PrincipalNameIndexResolver<>()); + new DelegatingIndexResolver<>(new PrincipalNameIndexResolver<>(PRINCIPAL_NAME_INDEX_NAME)); private final ConcurrentMap> sessionIdIndexMap = new ConcurrentHashMap<>(); @@ -35,14 +35,49 @@ public Mono save(MapSession session) { .then(updateIndex(session)); } - Mono updateIndex(MapSession session) { - return getIndexes(session.getId()) - .doOnNext(originalIndex -> indexSessionIdMap.computeIfPresent(originalIndex, + @Override + public Mono deleteById(String id) { + return super.deleteById(id) + .then(removeIndex(id)); + } + + @Override + public Mono> findByIndexNameAndIndexValue(String indexName, + String indexValue) { + var indexKey = new IndexKey(indexName, indexValue); + return Flux.fromIterable(indexSessionIdMap.getOrDefault(indexKey, Set.of())) + .flatMap(this::findById) + .collectMap(Session::getId); + } + + @Override + public Mono> findByPrincipalName(String principalName) { + return this.findByIndexNameAndIndexValue(PRINCIPAL_NAME_INDEX_NAME, principalName); + } + + @Override + public void destroy() { + sessionIdIndexMap.clear(); + indexSessionIdMap.clear(); + } + + Mono removeIndex(String sessionId) { + return getIndexes(sessionId) + .doOnNext(indexKey -> indexSessionIdMap.computeIfPresent(indexKey, (key, sessionIdSet) -> { - sessionIdSet.remove(session.getId()); + sessionIdSet.remove(sessionId); return sessionIdSet.isEmpty() ? null : sessionIdSet; }) ) + .then(Mono.defer(() -> { + sessionIdIndexMap.remove(sessionId); + return Mono.empty(); + })) + .then(); + } + + Mono updateIndex(MapSession session) { + return removeIndex(session.getId()) .then(Mono.defer(() -> { indexResolver.resolveIndexesFor(session) .forEach((name, value) -> { @@ -64,19 +99,18 @@ Flux getIndexes(String sessionId) { return Flux.fromIterable(sessionIdIndexMap.getOrDefault(sessionId, Set.of())); } - @Override - public Mono> findByIndexNameAndIndexValue(String indexName, - String indexValue) { - var indexKey = new IndexKey(indexName, indexValue); - return Flux.fromIterable(indexSessionIdMap.getOrDefault(indexKey, Set.of())) - .flatMap(this::findById) - .collectMap(Session::getId); + /** + * For testing purpose. + */ + ConcurrentMap> getSessionIdIndexMap() { + return sessionIdIndexMap; } - @Override - public void destroy() { - sessionIdIndexMap.clear(); - indexSessionIdMap.clear(); + /** + * For testing purpose. + */ + ConcurrentMap> getIndexSessionIdMap() { + return indexSessionIdMap; } record IndexKey(String attributeName, String attributeValue) { diff --git a/application/src/main/java/run/halo/app/security/session/ReactiveFindByIndexNameSessionRepository.java b/application/src/main/java/run/halo/app/security/session/ReactiveFindByIndexNameSessionRepository.java deleted file mode 100644 index e9c793e409..0000000000 --- a/application/src/main/java/run/halo/app/security/session/ReactiveFindByIndexNameSessionRepository.java +++ /dev/null @@ -1,24 +0,0 @@ -package run.halo.app.security.session; - -import java.util.Map; -import org.springframework.session.FindByIndexNameSessionRepository; -import org.springframework.session.PrincipalNameIndexResolver; -import org.springframework.session.Session; -import reactor.core.publisher.Mono; - -/** - * TODO: Wait for spring session 3.3 released and then remove this interface. - * if you want to remove this interface, please modify the {@link PrincipalNameIndexResolver} in - * {@link InMemoryReactiveIndexedSessionRepository} to have a parameterized constructor(since - * spring session 3.3) and overload the findByPrincipalName method. - */ -public interface ReactiveFindByIndexNameSessionRepository { - - String PRINCIPAL_NAME_INDEX_NAME = FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME; - - Mono> findByIndexNameAndIndexValue(String indexName, String indexValue); - - default Mono> findByPrincipalName(String principalName) { - return findByIndexNameAndIndexValue(PRINCIPAL_NAME_INDEX_NAME, principalName); - } -} diff --git a/application/src/main/java/run/halo/app/security/session/ReactiveIndexedSessionRepository.java b/application/src/main/java/run/halo/app/security/session/ReactiveIndexedSessionRepository.java index 7f18ab0b66..cc41a45def 100644 --- a/application/src/main/java/run/halo/app/security/session/ReactiveIndexedSessionRepository.java +++ b/application/src/main/java/run/halo/app/security/session/ReactiveIndexedSessionRepository.java @@ -1,5 +1,6 @@ package run.halo.app.security.session; +import org.springframework.session.ReactiveFindByIndexNameSessionRepository; import org.springframework.session.ReactiveSessionRepository; import org.springframework.session.Session; diff --git a/application/src/main/java/run/halo/app/security/session/SessionInvalidationListener.java b/application/src/main/java/run/halo/app/security/session/SessionInvalidationListener.java index 0892914150..4db189edc2 100644 --- a/application/src/main/java/run/halo/app/security/session/SessionInvalidationListener.java +++ b/application/src/main/java/run/halo/app/security/session/SessionInvalidationListener.java @@ -4,6 +4,7 @@ import lombok.RequiredArgsConstructor; import org.springframework.context.event.EventListener; import org.springframework.scheduling.annotation.Async; +import org.springframework.session.ReactiveFindByIndexNameSessionRepository; import org.springframework.session.ReactiveSessionRepository; import org.springframework.session.Session; import org.springframework.stereotype.Component; diff --git a/application/src/test/java/run/halo/app/security/session/InMemoryReactiveIndexedSessionRepositoryTest.java b/application/src/test/java/run/halo/app/security/session/InMemoryReactiveIndexedSessionRepositoryTest.java index c782f7d4d5..d944af1606 100644 --- a/application/src/test/java/run/halo/app/security/session/InMemoryReactiveIndexedSessionRepositoryTest.java +++ b/application/src/test/java/run/halo/app/security/session/InMemoryReactiveIndexedSessionRepositoryTest.java @@ -1,12 +1,20 @@ package run.halo.app.security.session; import static org.assertj.core.api.Assertions.assertThat; +import static org.springframework.session.ReactiveFindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME; +import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import reactor.test.StepVerifier; +/** + * Tests for {@link InMemoryReactiveIndexedSessionRepository}. + * + * @author guqing + * @since 2.15.0 + */ class InMemoryReactiveIndexedSessionRepositoryTest { private InMemoryReactiveIndexedSessionRepository sessionRepository; @@ -19,15 +27,81 @@ void setUp() { void principalNameIndexTest() { sessionRepository.createSession() .doOnNext(session -> { - session.setAttribute(ReactiveIndexedSessionRepository.PRINCIPAL_NAME_INDEX_NAME, + session.setAttribute(PRINCIPAL_NAME_INDEX_NAME, "test"); }) .map(session -> sessionRepository.indexResolver.resolveIndexesFor(session)) .as(StepVerifier::create) .consumeNextWith(map -> { assertThat(map).containsEntry( - ReactiveIndexedSessionRepository.PRINCIPAL_NAME_INDEX_NAME, + PRINCIPAL_NAME_INDEX_NAME, "test"); }); + + sessionRepository.findByPrincipalName("test") + .as(StepVerifier::create) + .expectNextCount(1) + .verifyComplete(); + + sessionRepository.findByIndexNameAndIndexValue( + PRINCIPAL_NAME_INDEX_NAME, "test") + .as(StepVerifier::create) + .expectNextCount(1) + .verifyComplete(); + } + + @Test + void saveTest() { + var indexKey = createSession("fake-session-1", "test"); + + assertThat(sessionRepository.getSessionIdIndexMap()).hasSize(1); + assertThat( + sessionRepository.getSessionIdIndexMap().containsValue(Set.of(indexKey))).isTrue(); + + assertThat(sessionRepository.getIndexSessionIdMap()).hasSize(1); + assertThat(sessionRepository.getIndexSessionIdMap().containsKey(indexKey)).isTrue(); + assertThat(sessionRepository.getIndexSessionIdMap().get(indexKey)).isEqualTo( + Set.of("fake-session-1")); + } + + @Test + void saveToUpdateTest() { + // same session id will update the index + createSession("fake-session-1", "test"); + var indexKey2 = createSession("fake-session-1", "test2"); + + assertThat(sessionRepository.getSessionIdIndexMap()).hasSize(1); + assertThat( + sessionRepository.getSessionIdIndexMap().containsValue(Set.of(indexKey2))).isTrue(); + + assertThat(sessionRepository.getIndexSessionIdMap()).hasSize(1); + assertThat(sessionRepository.getIndexSessionIdMap().containsKey(indexKey2)).isTrue(); + assertThat(sessionRepository.getIndexSessionIdMap().get(indexKey2)).isEqualTo( + Set.of("fake-session-1")); + } + + @Test + void deleteByIdTest() { + createSession("fake-session-2", "test1"); + sessionRepository.deleteById("fake-session-2") + .as(StepVerifier::create) + .verifyComplete(); + assertThat(sessionRepository.getSessionIdIndexMap()).isEmpty(); + assertThat(sessionRepository.getIndexSessionIdMap()).isEmpty(); + } + + InMemoryReactiveIndexedSessionRepository.IndexKey createSession(String sessionId, + String principalName) { + var indexKey = new InMemoryReactiveIndexedSessionRepository.IndexKey( + PRINCIPAL_NAME_INDEX_NAME, principalName); + sessionRepository.createSession() + .doOnNext(session -> { + session.setAttribute(indexKey.attributeName(), indexKey.attributeValue()); + session.setId(sessionId); + }) + .flatMap(sessionRepository::save) + .as(StepVerifier::create) + .verifyComplete(); + return indexKey; } } diff --git a/application/src/test/java/run/halo/app/security/session/ReactiveFindByIndexNameSessionRepositoryTest.java b/application/src/test/java/run/halo/app/security/session/ReactiveFindByIndexNameSessionRepositoryTest.java deleted file mode 100644 index a5a31b95e7..0000000000 --- a/application/src/test/java/run/halo/app/security/session/ReactiveFindByIndexNameSessionRepositoryTest.java +++ /dev/null @@ -1,15 +0,0 @@ -package run.halo.app.security.session; - -import static org.assertj.core.api.Assertions.assertThat; - -import org.junit.jupiter.api.Test; -import org.springframework.session.FindByIndexNameSessionRepository; - -class ReactiveFindByIndexNameSessionRepositoryTest { - - @Test - void principalNameIndexNameTest() { - assertThat(ReactiveFindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME) - .isEqualTo(FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME); - } -}