Получение ViewExpiredException в кластерной среде, в то время как метод сохранения состояния установлен на клиентский и пользовательский сеансы действителен

У меня есть приложение JSF, которое использует Mojarra 2.2.9 и развертывается в WebSphere 8.5.5.4 на кластеризованном environement и javax.faces.STATE_SAVING_METHOD установлено значение client.

Несмотря на то, что все мое приложение beans является областью действия запроса, иногда, когда пользовательский сеанс действителен, а пользователь выполняет почтовый запрос на странице, он получает ViewExpiredException. Что может быть причиной этой проблемы и как я могу ее решить? Будет ли изменение javax.faces.STATE_SAVING_METHOD на server решить проблему? Если да, каково влияние этого на память?

Кроме того, имеет ли это какое-либо отношение к кластеру environement и может быть какая-то недостающая конфигурация в Websphere, которая решит проблему?

Ответы

Ответ 1

Это произойдет, если состояние клиентской стороны зашифровано одним сервером и дешифровано другим сервером, и серверы не используют для этого один и тот же ключ AES. Как правило, вы также должны были видеть предупреждение ниже в журнале сервера:

ОШИБКА: MAC не подтвердил

Вам нужно убедиться, что вы установили jsf/ClientSideStateKey в web.xml с фиксированным ключом AES, иначе каждый сервер будет (повторно) генерировать свой собственный ключ 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>

Вы можете использовать этот фрагмент для создания случайного ключа AES256 (32 бит) в формате Base64.

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: недопустимый размер ключа или параметры по умолчанию?, установите расширение криптографии, как указано в ссылке, или создайте случайный AES128 ( 16 бит).

После ключа обязательно убедитесь, что вы не публикуете/не открываете свой ключ.

Кроме того, вам также необходимо убедиться, что вы добавили тег <distributable /> в web.xml, чтобы JSF выполнял более агрессивное сеансовое загрязнение, а сеансы HTTP (включая сам вид scoped beans!)) синхронизировались между серверами.

Еще одна возможная причина ViewExpiredException с сохранением состояния на стороне клиента - это то, что вы задали специфический для Mojarra контекст param com.sun.faces.clientStateTimeout в web.xml, который представляет время в секундах до того, как считается, что состояние входящей клиентской стороны истекло. Это, однако, маловероятно, так как этот контекстный параметр имеет довольно самоочевидное имя, которое вы бы заметили, просто взглянув на web.xml.

См. также:

Ответ 2

У вас должен быть дистрибутивный тег в вашем web.xml, как указано balusc