在启动的Spring WebSession中更新属性值的正确方法是什么?

时间:2018-01-19 17:46:47

标签: spring spring-session spring-webflux

我有SpringBoot 2.0.0.M7项目,我WebSession使用Redisorg.springframework.session:spring-session-data-redis:2.0.0.RELEASE)。

我有一个WebFlux路由,应该使用eBay会话ID重定向到eBay。每次用户访问该路由时,我都需要从eBay API请求不同的会话ID并将其包含在重定向URL中。之后,eBay会将用户重定向回我的应用程序,我需要该会话ID来请求令牌。

在测试期间,我发现当浏览器仍然具有包含现有会话ID的cookie时,会话属性的值(在我的情况下,它是ebay_session_id)不能用新值替换。在我再次请求ebay_session_id的路线中,我得到了旧的价值,而不是新的价值。

存储SessionID的代码如下:

return ebayApiReactiveWrapper
        .getSessionId(apiContext)
        .flatMap(sessionId ->
            request
                .session()
                .map(webSession -> {
                    webSession
                        .getAttributes()
                        .put("ebay_session_id", sessionId);

                    return sessionId;
                })
        )
        .flatMap(sessionId -> {
            final UriBuilder uriBuilder = uriBuilderFactory.uriString(
                ebayApiSettings.getSignInUrl()
            );

            uriBuilder.queryParam("runame", ebaySettings.getRuName());
            uriBuilder.queryParam("SessID", sessionId);

            return ServerResponse.temporaryRedirect(redirectUri).build();
        });

我尝试在webSession.save()方法之后添加put,但它没有帮助。

我做错了什么?提前谢谢!

更新

有关Redis中会话数据发生情况的一些新细节。创建会话时(空Redis),数据看起来像这样:

127.0.0.1:6379> hkeys "spring:session:sessions:cbbf8000-6ce8-4238-a427-9aab37d2702b"
1) "lastAccessedTime"
2) "maxInactiveInterval"
3) "creationTime"
4) "sessionAttr:ebay_session_id"

当我第二次访问相同路线时(会话cookie仍然存在且会话数据仍在Redis中),数据正在发生变化:

127.0.0.1:6379> hkeys "spring:session:sessions:cbbf8000-6ce8-4238-a427-9aab37d2702b"
1) "sessionAttr:ebay_session_id"

通过,sessionAttr:ebay_session_id仍然包含第一个请求的值。

最糟糕的是,当另一条路由尝试获取会话数据时,此类结构会导致NullPointerException。看起来它期待其他3个字段被呈现并且在不是这种情况时失败。

2 个答案:

答案 0 :(得分:0)

看起来没有多少人遇到过这样的问题。我找到了解决问题的解决方案。

如果未更改会话的属性集,我看到该会话不会更新。所以每次我需要更新会话值时,我都会添加一个新属性。问题代码中的第一个flatMap按以下方式更改:

.flatMap(sessionId ->
    request
        .session()
        .map(webSession -> {
            // we need to check if session already started before applying "hack"
            if (webSession.isStarted()) {
                // "hack"
                final DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yMdkmsn");
                webSession
                    .getAttributes()
                    .put(LocalDateTime.now().format(dateTimeFormatter),"1");
            }

            webSession
                .getAttributes()
                .put("ebay_session_id", sessionId);

            return sessionId;
        })
)

添加新属性后,会话被视为已更改,并将以redis更新。

答案 1 :(得分:0)

我遇到了这个问题并使用了几乎相同的hack,只是更新了原始类型的会话属性。

例如:

webSession.getAttributes().put("userContext", userContext);

webSession.getAttributes().put("lastContextUpdateTime", System.currentTimeMillis());

这可以避免为每个会话更新添加新属性,但也会在Redis中触发可变对象更新。