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

Getting ViewExpiredException in clustered environment while state saving method is set to client and user session is valid

我有一个使用 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 上缺少一些可以解决问题的配置?

您的 web.xml 中必须有 balusc

提到的可分发标签

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

ERROR: MAC did not verify

您需要确保在 web.xml 中使用固定的 AES 密钥设置 jsf/ClientSideSecretKey,否则每个服务器将在 startup/restart 期间(重新)生成自己的 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>

您可以使用此代码段生成 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: Illegal key size or default parameters? 错误,请按照 link 中的说明安装加密扩展,或者生成随机 AES128(16 位)密钥。

拿到钥匙后,绝对确保你没有publish/opensource你的钥匙。

此外,您还需要确保已将 <distributable /> 标记添加到 web.xml,以便 JSF 将执行更积极的会话脏化,并且 HTTP 会话(包括视图范围内的 bean 本身!)正确同步服务器。

客户端状态保存 ViewExpiredException 的另一个可能原因是您在 web.xml 中设置了特定于 Mojarra 的上下文参数 com.sun.faces.clientStateTimeout,它表示在传入的客户端状态被认为已过期。然而,这里的情况不太可能,因为上下文参数有一个相当不言自明的名称,您只需浏览一下 web.xml.

就会发现它

另请参阅:

  • javax.faces.application.ViewExpiredException: View could not be restored