У меня возникла проблема, на которую, надеюсь, вы сможете помочь. Предположим, я работаю для гипотетической компании под названием «Blammo», и у нас есть гипотетический продукт под названием «Log». Я пытаюсь создать систему, в которой кто-то может войти в logfromblammo.com и заказать некоторые из наших продуктов, а затем, когда они будут готовы купить, перейдите на checkout.blammo.com, чтобы оплатить их заказ. В конце концов, я хочу, чтобы Blammo запустил новый гипотетический продукт со своим собственным сайтом: rockfromblammo.com, и этот сайт также может поделиться сеансом с checkout.blammo.com, чтобы пользователи могли иметь одну корзину покупок по обоим продуктам веб-сайты.
Естественно, гипотетический сценарий, описанный выше, – это не то, как моя компания работает, но это прекрасный пример того, что мне нужно сделать. У нас есть существующая пользовательская база данных, и у нас есть способы аутентифицировать любого из наших пользователей на любом из наших сайтов, но цель, которую я имею, – позволить пользователям беспрепятственно переходить с одного сайта на другой без повторной аутентификации. Это также позволило бы нам беспрепятственно передавать данные, например, корзину покупок на сайт проверки.
Я (кратко) посмотрел на такие решения, как OpenID, но мне нужно иметь возможность интегрировать любое решение, имеющееся в нашем существующем методе аутентификации, что не является очень надежным. Есть ли хороший способ сделать это только с помощью PHP?
То, что вы можете сделать, это создать «перекрестные» связи между сайтами для переноса сеанса.
Самый простой способ – передать идентификатор сеанса через строку запроса; например
http://whateverblammo.com/?sessid=XXYYZZ
Прежде чем вы начнете думать, что кто-то может заманить эту информацию, подумайте о том, как переносятся ваши файлы cookie; предполагая, что вы не используете SSL, нет большой разницы для тех, кто использует сеть.
Это не значит, что это безопасно; во-первых, пользователи могут случайно скопировать / вставить адресную строку и тем самым протестировать сеанс. Чтобы ограничить эту экспозицию, вы можете сразу перенаправить на страницу без идентификатора сеанса после ее получения.
Обратите внимание, что использование mcrypt()
в идентификаторе сеанса не поможет, потому что это не видимость значения, это проблема; захват сеанса не заботится о базовом значении, а только о его воспроизводимости URL-адреса.
Вы должны убедиться, что идентификатор можно использовать только один раз; это можно сделать, создав переменную сеанса, которая отслеживает счет использования:
$_SESSION['extids'] = array(); $ext = md5(uniqid(mt_rand(), true)); // just a semi random diddy $_SESSION['extids'][$ext] = 1; $link = 'http://othersite/?' . http_build_query('sessid' => session_id() . '-' . $ext);
При получении:
list($sid, $ext) = explode('-', $_GET['sessid']); session_id($sid); session_start(); if (isset($_SESSION['extids'][$ext])) { // okay, make sure it can't be used again unset($_SESSION['extids'][$ext]); }
сlist($sid, $ext) = explode('-', $_GET['sessid']); session_id($sid); session_start(); if (isset($_SESSION['extids'][$ext])) { // okay, make sure it can't be used again unset($_SESSION['extids'][$ext]); }
Вам нужны эти ссылки каждый раз, когда пересекается граница, потому что сеанс, возможно, восстановился с последнего раза.
Это можно сделать, но не с помощью простых куки, и это не тривиально. То, что вам нужно, – это решение единого входа (SSO), похожее на имя пользователя Google, на котором есть доступ к сайтам i.google.com, gmail.com, youtube.com и т. Д.
Я использовал OpenID для реализации этого в прошлом.
Основная идея состоит в том, чтобы иметь единый домен аутентификации (Provider), когда один из сайтов (Consumer) хочет аутентифицировать пользователя, они перенаправляют их в домен аутентификации. Если они не вошли в систему, они могут войти в систему, используя любую необходимую информацию.
Если они уже вошли в систему (даже с другого целевого сайта), им не нужно снова входить в систему.
Затем пользователь отправляется обратно на целевой сайт с добавлением токена в URL-адресе. Этот токен используется сервером целевого сайта для проверки подлинности пользователя на сервере аутентификации.
Это очень простое объяснение. Делать это не сложно, сделать это безопасно гораздо больше. Детали создания и аутентификации токенов безопасно – сложная часть. Именно поэтому я предлагаю использовать хорошо продуманную систему, такую как OpenID.
Вам необходимо установить домен cookie сеанса следующим образом:
session_set_cookie_params($lifetime,$path,'.site.com')
Это будет работать, только если сайты находятся на одном доменном имени, включая TLD
(домен верхнего уровня).
См. Здесь для получения дополнительной информации
В качестве альтернативы, если вы пытаетесь получить доступ к перекрестным доменам сеансов, например, от site1.net
до site2.com
, это невозможно.
Если это нормально для вашего сайта, чтобы полагаться на Javascript для работы, вы могли бы предположительно сделать что-то вроде следующего:
Скажем, у вас есть сеанс на blammo.com, и вы хотите получить к нему доступ с сайта rockblammo.com. На странице rockblammo.com вы можете загрузить <script>
из blammo.com/get-session.js
, это будет (со стороны сервера) вернуть идентификатор сеанса. Как только это вернется, вы rockblammo.com/set-session.js?sessionId=XXX
новый <script>
на странице, указав на rockblammo.com/set-session.js?sessionId=XXX
, где XXX – это идентификатор сеанса, который вы только что получили от blammo.com. Теперь, на стороне сервера rockblammo.com, cookie сеанса обновляется и устанавливается на этот идентификатор сеанса. В дальнейшем обе страницы будут иметь один и тот же идентификатор сеанса, и если они будут иметь доступ к тому же хранилищу сеансов на бэкэнд, они будут синхронизированы.
Например, выход из blammo.com/get-session.js
будет:
var sessionId = "XXX"; var s = document.createElement("script"); s.src = "/set-session.js?sessionId=" + escape(sessionId); document.body.appendChild(s);
Выход из rockblammo.com/set-session.js
будет пустым, но будет включать заголовок http, например:
Set-Cookie: sessionId=XXX
Если вы предпочитаете не полагаться на Javascript, вы, вероятно, можете сделать то же самое, перенаправляя вперед и назад между двумя сайтами и передавая sessionId в параметре строки запроса (параметр GET).