Создание API для единого входа (SSO) с сторонним сайтом
Мой сайт должен интегрироваться со сторонним программным обеспечением, которое будет размещено на собственном поддомене, хостингом которого занимается компания-разработчик. Мне нужно предоставить сторонним разработчикам конечную точку API, через которую они смогут делать запросы к моему WordPress-сайту, чтобы пользователи моего сайта могли получить доступ к поддомену.
Другому сайту необходимо аутентифицировать пользователей моего сайта через какой-то API-интерфейс.
Я не совсем уверен, с чего начать, но мне кажется, что эту задачу уже решили люди умнее меня. Заранее спасибо за помощь!

Проблемы межсайтового скриптинга (XSS)
Вы не можете передавать аутентификационные куки WordPress между доменами. Также не рекомендуется хранить пароли в открытом виде для автоматического входа в другую установку WordPress. Поэтому пользователям придётся входить в WordPress, а затем получать статус их входа через API-эндпоинт с третьего сайта. Это позволяет WordPress обрабатывать всю аутентификацию. Такой подход достаточно безопасен, так как пользователь должен физически войти в WordPress, чтобы API-эндпоинт предоставил данные третьей стороне.
Создание API-эндпоинта
Ознакомьтесь с моей статьей: http://coderrr.com/create-an-api-endpoint-in-wordpress/
Также вы можете посмотреть демонстрацию кода здесь: https://gist.github.com/2982319
Вам нужно будет разработать логику под свои нужды, но этот метод позволит создать эндпоинт, через который можно передавать любые данные из WordPress.
Поскольку WordPress используется для аутентификации, можно проверить статус входа через функцию is_user_logged_in()
. Если вход выполнен, можно вернуть объект пользователя с необходимыми данными для третьей стороны.
Вход с третьей стороны
С третьего сайта можно добавить ссылку на страницу входа для удобства, используя параметр redirect_to
. После входа пользователь будет перенаправлен обратно на сторонний сайт.
http://sub.yourdomain.com/wp-login.php?redirect_to=http%3A%2F%2Fwww.third-party-domain.com
Удалённый вход
Если требуется авторизовывать пользователей в WordPress с третьего сайта, можно использовать функции WordPress, описанные здесь: http://kuttler.eu/code/log-in-a-wordpress-user-programmatically/
Обязательно используйте общий секретный ключ и временные хеши на его основе для безопасности. Примерный процесс выглядит так:
Третья сторона отправляет запрос с временной меткой и токеном, сгенерированным на основе общего секрета:
$shared_secret = 'foobar'; //не передавать этот ключ в API-эндпоинт
$timestamp = time();
$token = md5($shared_secret.$time_stamp);
Установка WordPress получает запрос:
$shared_secret = 'foobar';
$timestamp = esc_attr($_GET['timestamp']);
if((time() - $timestamp) > 30) # Порог 30 секунд
//здесь можно обработать истёкший токен!
$token = md5($share_secret.$timestamp);
$token_to_check = esc_attr($_GET);
if($token == $token_to_check)
//аутентификация успешна!

Довольно уверен, что стороннее ПО не имеет никакого отношения к WP, так что по сути это единый вход (SSO), но с WordPress в роли провайдера аутентификации.

@Brian: Меня заинтересовала идея перехода на мультисайтовую установку, но я не до конца понимаю ваш аргумент насчёт cookies. Всё, что нужно - чтобы стороннее ПО могло проверить, что его пользователь действительно является моим пользователем. В остальном ПО самодостаточно и может использовать собственные cookies или что-то ещё.

@Emerson Теперь я понимаю. Извините за путаницу. Вы можете использовать идею конечной точки, которую я создал, и использовать общий токен в метаданных пользователя для аутентификации. Возвращайте JSON-ответ третьей стороне, если пользователь существует.

Спасибо, Brian. Я внимательнее изучил ваш код и, кажется, начинаю понимать ваше решение. Не могли бы вы показать небольшой пример кода, чтобы проиллюстрировать, как ваш плагин будет работать в моем приложении? Я посмотрел исходный код, но пока не до конца разобрался.

Если быть более конкретным, меня интересует, как адаптировать ваш плагин для моих целей. Нужно ли заменить это: protected $api = 'http://pugme.herokuapp.com/bomb?count=';
на protected $api = http://mydomain.com/api/...
, поскольку мой скрипт будет проверять данные в моей базе данных, а не в стороннем API... ?

@Emerson Вам действительно не нужно использовать переменную api, так как вы будете делать запрос к базе данных WP вместо использования конечной точки для стороннего API. Вы можете просто удалить это. Вся магия происходит в add_rewrite_rule(); Если у вас есть дополнительные вопросы, свяжитесь со мной на моем сайте.

@Brian огромное спасибо, это отличное решение! У меня есть вопрос. Должен ли запрос от стороннего приложения к конечной точке выполняться на стороне клиента? Я попробовал это локально: когда я делаю запрос прямо в браузере, я получаю правильный ответ "пользователь авторизован" от конечной точки, но когда я делаю это со страницы PHP - нет. Я предполагаю, что мне нужно запрашивать статус авторизации из браузера, потому что серверная сторона не знает о статусе.

Мне не удалось заставить этот подход работать, несмотря на несколько дней работы.

Очень хорошее решение. Может возникнуть проблема, если приложения установлены на разных серверах и по какой-то причине время на каждой машине отличается. Я бы предложил использовать counter
вместо time()
и передавать его с запросом. Обе стороны сохраняют последний переданный счетчик, и когда API получает запрос с новым счетчиком, он проверяет, что новый больше предыдущего. Таким образом, задержка не может нанести вред.
