在集群环境中,当状态保存方法设置为客户端且用户会话有效时,出现 ViewExpiredException

问题描述 投票:0回答:2

我有一个使用 Mojarra 2.2.9 的 JSF 应用程序 并部署在集群环境的WebSphere 8.5.5.4上 并且

javax.faces.STATE_SAVING_METHOD
设置为
client

即使我的所有应用程序 bean 都是请求范围的,有时当用户会话有效并且用户在页面上执行 post 请求时,他会得到

ViewExpiredException
。可能是什么原因导致此问题以及如何解决? 将
javax.faces.STATE_SAVING_METHOD
更改为
server
可以解决问题吗?如果是这样,这样做对记忆有什么影响?

另外,这与集群环境有什么关系吗?也许 Websphere 上缺少一些配置可以解决该问题?

jsf websphere jsf-2.2 websphere-8 viewexpiredexception
2个回答
13
投票

如果客户端状态由一台服务器加密并由另一台服务器解密,并且服务器不使用相同的 AES 密钥,就会发生这种情况。通常,您还应该在服务器日志中看到以下警告:

错误:MAC 未验证

您需要确保已使用固定的 AES 密钥在

jsf/ClientSideSecretKey
中设置
web.xml
,否则每个服务器将在启动/重新启动期间(重新)生成自己的 AES 密钥(在加密视图状态期间使用)。

<env-entry>
    <env-entry-name>jsf/ClientSideSecretKey</env-entry-name>
    <env-entry-type>java.lang.String</env-entry-type>
    <env-entry-value>[AES key in Base64 format]</env-entry-value>
</env-entry>

注意:自 Faces 4.0 起,它已重命名为

faces/ClientSideSecretKey

您可以使用此代码片段生成 Base64 格式的随机 AES256(32 位)密钥。

KeyGenerator keyGen = KeyGenerator.getInstance("AES");
keyGen.init(256); // Use 128 for 16bit key.
String key = Base64.getEncoder().encodeToString(keyGen.generateKey().getEncoded());
System.out.println(key); // Prints AES key in Base64 format.

如果您收到 Java Security:非法密钥大小或默认参数?错误,请按照链接中的说明安装加密扩展,或者生成随机 AES128(16 位)密钥。

获得密钥后,请绝对确保您不会发布/开源您的密钥。

此外,您还需要确保已将

<distributable />
标记添加到
web.xml
,以便 JSF 将执行更积极的会话脏污,并且 HTTP 会话(包括视图作用域 bean 本身!)在服务器之间正确同步。

客户端状态保存导致

ViewExpiredException
的另一个可能原因是您在
com.sun.faces.clientStateTimeout
中设置了Mojarra特定的上下文参数
web.xml
,它表示传入客户端状态被视为过期之前的时间(以秒为单位)。然而,这种情况不太可能发生,因为上下文参数有一个相当不言自明的名称,您只需浏览一下即可发现
web.xml

另请参阅:


2
投票

您的 web.xml 中必须具有 balusc 提到的可分发标签

© www.soinside.com 2019 - 2024. All rights reserved.