我有一个使用 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 上缺少一些配置可以解决该问题?
如果客户端状态由一台服务器加密并由另一台服务器解密,并且服务器不使用相同的 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
。
您的 web.xml 中必须具有 balusc 提到的可分发标签