Вопрос или проблема
Мы используем WordPress с плагином OpenID Connect Generic Client для предоставления SSO с помощью Keycloak. В настоящее время мы ищем способ выхода пользователей из WordPress без необходимости их посещения WordPress в браузере. Мотивация заключается в том, что второй веб-сайт (клиент) также подключен к Keycloak, и мы хотим, чтобы пользователи выходили из обоих клиентов, как только они нажимают кнопку выхода на одном из них.
Для достижения этой цели мы хотим использовать OpenID Connect Backchannel Logout. Идея заключается в том, что в Keycloak для каждого клиента указана URL-адрес выхода по заднему каналу. Когда пользователь выходит из любого из клиентов, Keycloak отправляет определенную информацию (например, UUID пользователя) на оба URL-адреса выхода по заднему каналу и запрашивает у клиентов выход пользователя.
Как мы понимаем, эта функция недоступна в WordPress, по крайней мере, с плагином OpenID Connect Generic Client. Чтобы это обойти, мы настроили отдельное приложение, которое запускает wp user session destroy –all для конкретного пользователя, когда он выходит из любого другого клиента.
Хотя это уже работает в другом направлении (выход из WordPress автоматически инициирует выход в другом клиенте), в настоящее время мы не можем выходить из пользователей WordPress таким способом, так как кука wordpress_logged_in_ остается действительной. Мы проверили, что одной куки достаточно, чтобы снова войти в систему. Мне удалось это сделать, вручную добавив ее в Chrome DevTools с ключом и значением, полученными от моего коллеги.
- Мы предполагаем, что кука больше не должна позволять повторный вход после выполнения wp user session destroy –all. Неправильно ли это предположение?
- Существует ли способ аннулировать эту куку через WP CLI без добавления пользовательского кода?
- Если нет, каков лучший способ полностью выходить из пользователей в этом сценарии?
Мы предполагаем, что кука больше не должна позволять повторный вход после выполнения wp user session destroy –all. Неправильно ли это предположение?
Кука никак не связана с повторным входом, эта команда уничтожит их текущие активные сессии и не имеет отношения к будущим сессиям.
Пользователь может создать новые сессии, войдя в систему, но вы можете предотвратить это через реализацию SSID. На этом этапе это уже не вопрос WordPress, а вопрос OpenID Connect. Если он позволяет им войти снова, будет создана новая сессия, если нет — то сессия не создается, так как для ее создания необходим успешный вход.
Существует ли способ аннулировать эту куку через WP CLI без добавления пользовательского кода?
Четыре альтернативных метода:
- Отредактировать пользователя в WP Admin и нажать кнопку “выйти везде”
- Получить объект менеджера сессий пользователей через
$manager = WP_Session_Tokens::get_instance( get_current_user_id() );
, затем вызватьdestroy_all()
на полученном объекте. - Вручную удалить сессии в SQL (учтите, что это несет риск, поскольку не будут запущены хуки, очищены кеши и кэши объектов и т.д.)
- С помощью CLI вы можете стереть мета-пользователя, который хранит сессии. Это безопаснее, чем использовать сырую SQL-запрос, и очищает кеши мета-пользователя по мере необходимости, но не запускает соответствующие хуки и все равно несет некоторый риск, который будет обрабатываться командой CLI, которую вы упомянули.
Если нет, каков лучший способ полностью выходить из пользователей в этом сценарии?
Удаление сессии через WP CLI или с помощью фрагмента кода достаточно для аннулирования куки и заставляет пользователя войти и создать новую сессию. Существующая сессия и любые куки, которые она поддерживала, становятся неэффективными и аннулированными в результате удаления сессий.
Мои рекомендации:
- Для WP CLI используйте команду
wp user session destroy
, которую вы уже используете. - Для PHP-кода используйте фрагмент кода менеджера токенов сессии.
Общая заметка о сессиях
В пользовательском мета хранится список текущих активных/действительных сессий, и кука ссылается на это. Удаление этих сессий означает, что куки больше не могут быть использованы, и необходимо создать новые. Это работает также, как кнопка “выйти везде” на странице профиля пользователя, и не требуются посещения браузера или удаление куки.
https://developer.wordpress.org/reference/functions/wp_destroy_all_sessions/
wp_destroy_all_sessions
удалит все сессии для текущего авторизованного пользователя.
Также хотел бы отметить, что этот список содержит активные сессии, и как только сессия больше неактивна, она удаляется, так что она не может быть использована для того, чтобы выяснить, когда пользователь в последний раз входил в систему. Любая система, которая делает это, может быть обманута, если пользователь выйдет, чтобы удалить сессию из списка.
Кроме того, это не PHP-сессии, они являются отдельной вещью, которая не используется WordPress и имеет свои последствия и проблемы совместимости.
Мы используем WordPress с плагином OpenID Connect Generic Client для предоставления SSO с помощью Keycloak.
Обратите внимание, что вы также должны потратить время на изучение этого плагина, здесь могут быть даны ответы только для общего WordPress, и этот плагин может вмешиваться в систему или изменить ее работу, хотя это маловероятно.
.
Ответ или решение
Чтобы обсудить вопрос об аннулировании cookie «wordpress_logged_in» через механизм обратного канала выхода, необходимо рассмотреть некоторые важные аспекты, связанные с текущей реализацией системы единого входа (SSO) на базе Keycloak и WordPress.
Теория (Theory)
Когда пользователь входит в систему WordPress через SSO с помощью плагина OpenID Connect Generic, создается cookie «wordpress_logged_in», которая поддерживает активную пользовательскую сессию. При необходимости разлогина всех клиентов сразу (например, при клике по кнопке выхода в любом из связанных сайтов), важно, чтобы сессия пользователя во всех приложениях была аннулирована.
В контексте обратного канала выхода OpenID Connect (Backchannel Logout), Keycloak отправляет запросы на заданные URL-адреса, уведомляя каждый клиент о выходе из системы. Однако WordPress и используемый вами плагин, возможно, не поддерживают эту функциональность напрямую, что заставляет искать обходные пути.
Пример (Example)
Вы уже реализовали механизм, при котором разлогин из WordPress инициирует выход и из других клиентов, однако в обратном направлении эта взаимосвязь не работает. Использование команды wp user session destroy --all
через отдельное приложение уничтожает текущие активные сессии, но проверка показала, что cookie остается действительной.
Применение (Application)
1. Предположения о действительности cookie
Команда wp user session destroy --all
действительно уничтожает активные сессии, однако cookie может быть актуальной до полного ее обновления. Процесс уничтожения сессии должен автоматически сделать cookie недействительной, однако, если вы замечаете обратное, возможно, происходит что-то еще.
2. Инвалидация cookies через WP CLI без использования пользовательского кода
На данный момент, стандартного метода в WP CLI, который бы инвалдировал cookie без написания пользовательского кода, может не существовать. Однако рассмотрите следующие способы:
- Использование функции
wp_destroy_all_sessions()
для уничтожения всех сессий пользователя. - Как альтернатива, программаторное использование
WP_Session_Tokens::get_instance()->destroy_all()
может быть полезным.
3. Рекомендации по полной деавторизации пользователей
Лучшим вариантом является использование существующих команд WP CLI или использование API WordPress для работы с токенами сессий. Это позволит поддерживать актуальность системы и облегчит реализацию бизнес-логики, необходимой для вашего проекта:
- Используйте команду WP CLI
wp user session destroy
для устранения текущих сессий; - Через PHP-код используйте менеджер токенов.
Также убедитесь, что изучили и особенности плагина OpenID Connect Generic, поскольку он может влиять на этот процесс.
Подытоживая, для обеспечения корректного выхода пользователей через механизмы, рекомендую детально анализировать действия Keycloak и взаимодействие с плагином OpenID. Это позволит адаптировать работу системы под ваши требования, минимизировав использование workaround-решений.