Как проверить пользователя вне WordPress/PHP?
Я работаю над AJAX-приложением, которое будет встроено в страницу WordPress. Приложение обменивается данными с сервлетами, работающими на Tomcat. Сервлетам необходимо определить, приходит ли запрос от пользователя, авторизованного в WordPress, и получить его ID для запросов к базе данных. Если пользователь не авторизован, запрос должен быть отклонен.
Другими словами, сервлет должен выполнять запрос только если пользователь, инициировавший его, авторизован в WordPress (версия 3.3.x). И сервлет (Tomcat), и WordPress (Apache2) работают на одном физическом сервере и используют общую базу данных.
Теоретически это можно реализовать следующим образом:
- При авторизации в WordPress некий токен пользователя сохраняется в JavaScript-переменной.
- AJAX-приложение передает этот токен сервлетам при каждом запросе.
- Сервлеты проверяют валидность токена (т.е. факт авторизации пользователя) и выполняют или отклоняют запрос.
Вопрос: как это можно реализовать на стороне WordPress?
Сложность в том, что у меня пока нет опыта программирования на PHP.
Первоначально я думал о передаче куки wordpress_logged_in (auth) сервлету и проверке его валидности через WordPress, но функция wp_validate_auth_cookie() всегда возвращает ошибку, даже при передаче данных авторизованного пользователя.
Другой вариант - создать плагин, который будет сохранять sessionid и userid в таблицу, доступную для запросов сервлетов. Или, возможно, есть другие решения...

В WordPress уже есть встроенный API через XMLRPC сервер. Это означает, что вы можете сделать XMLRPC запрос из вашего Java приложения и проверить имя пользователя/пароль. К сожалению, нет возможности просто пройти аутентификацию через него в текущем виде.
Тем не менее, очень легко создать свой собственный метод. Просто подключитесь к фильтру xmlrpc_methods
и добавьте свой. Ключ массива, который вы добавите, будет методом XMLRPC, вызываемым из вашего приложения, а значение - функцией, которая будет вызываться сервером WordPress XMLRPC.
<?php
add_filter('xmlrpc_methods', 'wpse39662_add_login_method' );
/**
* Фильтрует методы XMLRPC, чтобы позволить проверять только логин/пароль
* для заданного пользователя
*/
function wpse39662_add_login_method( $methods )
{
$methods['wpse39662.login'] = 'wpse39662_check_login';
return $methods;
}
И callback-функция wpse39662_check_login
получит один аргумент - массив данных, отправленных на сервер XMLRPC.
<?php
function wpse39662_check_login( $args )
{
$username = $args[0];
$password = $args[1];
$user = wp_authenticate( $username, $password );
if( is_wp_error( $user ) )
{
return false;
}
return true;
}
Вот весь этот код в виде плагина. После установки этого плагина и включения XMLRPC на вашем сайте WordPress, вы сможете делать запросы с помощью любого XMLRPC клиента (уверен, в Java такой есть).
Вот код, который я использовал для тестирования вышеописанного (клиент XMLRPC на Python).
>>> import xmlrpclib as xmlrpc
>>> s = xmlrpc.ServerProxy('http://wordpress.dev/xmlrpc.php')
>>> s.wpse39662.login('admin', 'password')
True

Спасибо! Это значительно продвигает меня вперед! Можно ли достичь того же, используя аутентификационную cookie пользователя? Чтобы не хранить и не передавать логин/пароль по сети? Мой проект представляет собой ajax-приложение, встроенное в страницу WordPress. Ajax-приложение вызывает сервлет, а сервлет проверяет в WordPress, аутентифицирован ли пользователь. Я мог бы передать логин/пароль в ajax-приложение и отправить его в сервлет, но боюсь, что это не очень безопасно. Поэтому я попытался передать содержимое аутентификационной cookie в wp_validate_auth_cookie(), но это всегда завершается ошибкой.

WordPress (в настоящее время) проверяет, остался ли пользователь авторизованным, проверя один из файлов cookie, которые он выдает при входе в систему. Содержимое этого cookie формируется путем хеширования. Подробности можно найти в функции "wp_generate_auth_cookie" в файле /wp-includes/pluggable.php:
function wp_generate_auth_cookie($user_id, $expiration, $scheme = 'auth') {
$user = get_userdata($user_id);
$pass_frag = substr($user->user_pass, 8, 4);
$key = wp_hash($user->user_login . $pass_frag . '|' . $expiration, $scheme);
$hash = hash_hmac('md5', $user->user_login . '|' . $expiration, $key);
$cookie = $user->user_login . '|' . $expiration . '|' . $hash;
return apply_filters('auth_cookie', $cookie, $user_id, $expiration, $scheme);
}
Вы можете воссоздать этот алгоритм (используя эту и другие функции auth_cookie) в своем Java-коде для выполнения аналогичных проверок. Для передачи cookie в ваш сервлет можно использовать JavaScript.
В качестве альтернативы можно рассмотреть использование XMLRPC. Вы можете написать новый метод (как объясняется в другом решении) для проверки auth cookie (вместо обычной проверки имени пользователя и пароля).

Установите плагин Exec-PHP, затем создайте страницу в WordPress (не запись) с удобным постоянным адресом (http://mysite/user_id/
) и разместите код из справочника по API get_current_user_id()
:
<?php
$user_id = get_current_user_id();
if ($user_id == 0) {
echo 'Вы не авторизованы.';
} else {
echo 'Вы авторизованы как пользователь '.$user_id.'.';
}
?>
Затем вы можете извлечь cookies, отправленные клиентом, и передать их в GET
-запросе на http://127.0.0.1/user_id/
. Это позволит вам определить, авторизован ли пользователь и узнать его ID.

Спасибо за ответ. Проблема в том, что сервлеты написаны на Java, поэтому PHP-код не может быть выполнен. Мне нужно что-то вроде внешнего интерфейса, который позволит сервлету/Java общаться с WordPress/PHP. Наверняка есть какой-то интерфейс, просто я не могу его найти...

А, понятно. Возможно, использование чего-то вроде Quercus http://www.caucho.com/resin-3.0/quercus/ даст вам лучшее из обоих миров?

Спасибо, но Quercus — это не то решение, так как у меня уже работают WordPress/PHP/Apache и сервлет/Java/Tomcat. Теперь мне нужен только интерфейс между этими двумя системами, который позволит сервлету проверять, авторизован ли пользователь в WordPress (какой-то интерфейс/протокол/межпроцессное взаимодействие/что угодно).

Это одностраничный плагин для WordPress, который выполняет задачу:
function yournamespace_validateAuthCookie($cookie, $scheme = 'logged_in') {
return wp_validate_auth_cookie($cookie, $scheme);
}
function yournamespace_new_xmlrpc_methods($methods) {
$methods['yournamespace.validateAuthCookie'] = 'yournamespace_validateAuthCookie';
return $methods;
}
add_filter('xmlrpc_methods', 'yournamespace_new_xmlrpc_methods');
По сути, он предоставляет новый метод XML-RPC, с помощью которого можно запросить у WordPress проверку куки wordpress_logged_in_...
.
Затем вам нужно написать код для вызова этого метода, передав ему значение куки wordpress_logged_in_...
.
Метод вернет либо false
(если куки не прошли проверку), либо ID пользователя в случае успешной валидации.
