Система на подобии Microsoft Passport на PHP (межсайтовая авторизация)

Статус
В этой теме нельзя размещать новые ответы.

KostyaCat

мы где-то рядом
но и выводить их побольшей части с каждым постом в форуме мне кажется лишним. =)

А вообще никто не мешает вести локальную базу с необходимыми данными.

Цель сервиса, насколько я понимаю, избавить пользователя от n-го множества регистраций и авторизаций.

А не экономии места на хостинге. Покрайней мере, я на это надеюсь =)
 

Vasya

Guest
Вот, некий результат.
Есть два домена: MAIN -- 127.0.0.1 и SECOND - 127.0.0.2. У обоих все происходит в папке /cross_session/ -- чисто для удобства тестирования.
Без JavaScript'a.
Абстрактно, imho, проблема такова :)
- на первом сайте чел авторизуется
- попадает на второй сайт
- шлет запрос на первый сайт
- там, из КУКИ, поднимается сессия с информацией об авторизаци на первом сайте
- по СКРЫТОМУ(!) каналу сайты договариваются об авторизации на втором сайте

Проверить можно так:
- заходим на http://127.0.0.1/cross_session/index.php?l=vasya&p=pupkin
- закрываем браузер
- заходим на http://127.0.0.2/cross_session/domain2.php
- видим, что мы авторизованы.

index.php
------------
PHP:
<? // index.php; MAIN domain; 127.0.0.1
session_start();

if( $_SESSION["authorized"] !== true ) {
	if($_REQUEST["l"]=="vasya" && $_REQUEST["p"]=="pupkin") {
		$_SESSION["authorized"] = true;
	}
}

?><html><body>MAIN domain<hr>
<?
if( $_SESSION["authorized"] !== true ) {
?><form method=get action="">
login:<input type="text" name="l"><br>
password:<input type="password" name="p"><br>
<input type="submit">
</form><hr>
<?}?>
_SESSION["authorized"]:'<?=$_SESSION["authorized"]?>'<hr>
<a href="http://127.0.0.2/cross_session/domain2.php">domain #2</a>
</body></html>
getsess_id.php
------------
PHP:
<?// getsess_id.php; MAIN domain; 127.0.0.1
session_start();
if(!empty($_GET["sess2"])) {
	// (!) here we have two session_ids
	;
}
header("Location: http://127.0.0.2/cross_session/domain2.php?sess1=".session_id());
exit();
?>
domain2.php
------------
PHP:
<?//domain2.php; SECOND domain; 127.0.0.2
session_start();
if( ! session_is_registered("authorized") ) {
	if( ! empty($_REQUEST["sess1"])) {
		// hidden channel
		$s = file("http://127.0.0.1/cross_session/get_auth.php?PHPSESSID=".$_REQUEST["sess1"]);
		echo "HIDDEN CHANNEL<br>";
		echo "s[0]=".$s[0]."<br>";
		parse_str($s[0]);
		$_SESSION["authorized"] = ($domain_1_authorized == "1");
	} else {
//	(!)	header("Location: http://127.0.0.1/cross_session/getsess_id.php?sess2=".session_id());
		header("Location: http://127.0.0.1/cross_session/getsess_id.php");
		exit();
	}
}

?><html><body>SECOND domain page<hr><?
if($_SESSION["authorized"]) {
	echo "User authorized in MAIN domain.";
} else {
	echo "User NOT authorized in MAIN domain.";
}
?></body></html>
get_auth.php
------------
PHP:
<?//get_auth.php; MAIN domain; 127.0.0.1
session_start();
echo "domain_1_authorized=".$_SESSION["authorized"];
?>
 

Vasya

Guest
P.S. Прошу помнить, что это не промышленный вариант, а только демонстрация.
Например, если юзер СНАЧАЛА заходит на второй домен, а потом уже на первый, то авторизация на втором не появится даже после авторизации на первом... Ну, в "промышленном" варианте, это легко обходится сравнением времен захода на сайты... и т.п...
 

NEK

Guest
с одного домена нельзя прочесть/поставить куку для другого.
А если заменить все ссыки (как делает РНР)
- сначала было: <a href="http://www.zlo.ru">dfg</>
/* тут идут преобразования /**/
- потом:<a href="htpp://kpss7.ru/check.php?st=http://www.zlo.ru&login=$login&pass=$pass">dfg</>

И все тут.

А check.php сокетом выдирает заданые страницы и меняет ссылки
 

Popoff

popoff.donetsk.ua
читаем РФС, например здесь: http://www.ietf.org/rfc/rfc2109.txt
там написано, что:

1. Оставлять куки для других доменов можно
2. Если оставляем куки для других доменов, то должны указать доменный суффикс.
3. Нельзя в качестве доменного суффикса указывать домен первого или нулевого уровня. Т.е. минимум - aaa.bbb.
4. Нельзя в качестве домена указывать ип-адрес
5. В начале доменного суффикса нужно поставить точку.
6. Домен, который ставит куки, должен сам подходить под тот доменный суффикс, которому он ставит куки. Т.е. нельзя оставить куки с домена, например qqq.www.eee для доменного суффикса .wer.eee
7. Нельзя ставить куки для доменов, которые более чем на один уровень отличаются от доменного суффикса, т.е. если указываем доменный суффикс .wer.eee, то с домена qqq.www.wer.eee куки не будут видны, потому что отличие больше чем на один уровень.

Там даже примеры есть, из которых все понятно:

* A Set-Cookie from request-host y.x.foo.com for Domain=.foo.com
would be rejected, because H is y.x and contains a dot.

* A Set-Cookie from request-host x.foo.com for Domain=.foo.com would
be accepted.

* A Set-Cookie with Domain=.com or Domain=.com., will always be
rejected, because there is no embedded dot.
думаю, именно так и реализована авторизация на passport.yandex.ru. У них же ш все службы на yandex.ru заканчиваются. Попробуйте зайти на narod.ru - он вас автоматически переборсит на narod.yandex.ru :) Я только сейчас понял, зачем он это делает %)

Там, кстати, есть еще один пример:

* A Set-Cookie with Domain=ajax.com will be rejected because the
value for Domain does not begin with a dot.
Это означает, что нельзя указывать конкретный домен, допустимы только суффиксы, а значит куки будут передаваться другим доменам, которые заканчиваются на этот суффикс. Но...
To make the cookie available on all subdomains of example.com then you'd set it to '.example.com'. The . is not required but makes it compatible with more browsers. Setting it to www.example.com will make the cookie only available in the www subdomain.
Это уже от браузера зависит, установит он такой куки или нет.
Но если браузер не поддерживает домен без точки в начале, то он вообще такой куки не установит.
 

grigori

( ͡° ͜ʖ ͡°)
Команда форума
думаю, на самом деле все проще
условия:
1. сессии всех сайтов хранятся вместе (NFS, DB)
2. Есть сайт авторизации
Действия:
1. юзер заходит на 1й сайт, авторизации нет, стартуем новую сессию, останавливаем сессию (не убиваем)
2. выдаём редирект на сайт авторизации с SID в GET
3. сайт авторизации (СА) получает SID, смотрит, что такая сессия есть, влазит в сессию, которую открыл другой сайт, ставит себе куку, в которой SID, делает редирект на себя, чтоб куку записать в браузер
(большинству остальное уже понятно)
4. авторизация, запись данных в сессию
5. редирект на сайт, откуда пришли
6. пришли на другой сайт
7. редирект на СА с SID в GET
8. СА видит старую куку (позаботьтесь, чтоб она не умирала за пол-часа),
а) запускает старую сессию (котрая жива, т.к. мы работали с ней на старом сайте), считывает оттуда данные, закрывает её, открывает новую (проверил, выдает ворнинг, что headers посланы, но работает) и записывает данные из старой сессии в новую, дальше по плану,
б) отдаёт сайту 2 SID сессии от сайта 1, который сайт 2 подключает себе

можно ли SID отдавать по GET? да, не хочется, но что делать...
ну а всё-таки если вы банкинг пишите,
можно сделать 3ю временную сессию, которая умрёт сразу после перехода с сайта на сайт и в ней передавать SID постоянной сессии
 

Ямерт

The Old One
можно ли SID отдавать по GET? да, не хочется, но что делать...
GET, POST - какая в данном случае разница? Если есть нюхалка, передаваемый SID она всё равно узнает. Можно подумать над шифровкой SID, или разбивкой его на части.
 

NEK

Guest
Автор оригинала: grigori
Действия:
1. юзер заходит на 1й сайт, авторизации нет, стартуем новую сессию, останавливаем сессию (не убиваем)
2. выдаём редирект на сайт авторизации с SID в GET
3. сайт авторизации (СА) получает SID, смотрит, что такая сессия есть, влазит в сессию, которую открыл другой сайт, ставит себе куку, в которой SID, делает редирект на себя, чтоб куку записать в браузер
Т.е. надо постоянно обращаться к авторизации. Т.е. постоянно открытый сокет на сайт №1.
И вообще насчет передачи $_GET (идея Demiurg) ->
PHP:
$st='http://www.fignya.com/autorize.php?login_pass='.md5($login':'$pass).'&chislo='.$chislo;
  А обратно вида ->
$str=md5(serialize($_SESSION).':'.md5($chislo));
И сессию на серваке который требывал авторизации. По другому убъешь сервак.
 

grigori

( ͡° ͜ʖ ͡°)
Команда форума
Автор оригинала: NEK
Т.е. надо постоянно обращаться к авторизации. Т.е. постоянно открытый сокет на сайт №1.
Нет. Переход на сайт авторизации 1 раз для авторизации.
И вообще насчет передачи $_GET (идея Demiurg) ->
PHP:
$st='http://www.fignya.com/autorize.php?login_pass='.md5($login':'$pass).'&chislo='.$chislo;
  А обратно вида ->
$str=md5(serialize($_SESSION).':'.md5($chislo));
И сессию на серваке который требывал авторизации. По другому убъешь сервак.
Что значит "сессию на серваке который требывал авторизации"?
 

NEK

Guest
Автор оригинала: grigori
Что значит "сессию на серваке который требывал авторизации"?
Т.е. на сайте c которого пришел пользователь. Все равно ГЕТ-ом будешь отсылать, что ОК !!!
 

Baster

Guest
кстати , проблемма как понял так и нашла реального ответа ?
Потому как такая штука очень нужна ...
 

Фанат

oncle terrible
Команда форума
Baster, а ты учи протокол HTTP.
И сразу узнаешь - и как решать проблему, и что можно решить, а что - нет.
Там все очень просто, если понимать, как работает.
 

ForJest

- свежая кровь
Ты неправильно понял. Проблему решили. Если ты удосужишься внимательно изучить весь тред и попробовать все изложенные здесь идеи, то у тебя будет даже несколько вариантов.
 

FiLLiN

Guest
Народ, я вообще не понимаю о чем такая длинная дискусия.

Единственное верное решение (по трудоемкости, надежжности и изящности) это использование сессий, с сохранением данных в БД и передачей SESSION_ID в урле GET методом. Остальные решения либо небезопасны либо несостоятельны.
 

NEK

Guest
Не знаю может это тупо, но
auth-x.php ->
PHP:
<?session_start();?>
<?include_once($_SERVER['DOCUMENT_ROOT'].'/lib/uses.phl');uses('dump');?>
<?
/* Если сервер присылает пользователя проверить ,
*  авторизирован он или нет с своим обратным адрессом
*  $_GET['url_from']
*/
 $preview_server='127.0.0.8';
 $current_server='127.0.0.7';
 $next_server='127.0.0.8';

 if(strpos($_GET['url_from'], $preview_server)!==false&&!empty($_SESSION['authorized'])){
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, "http://$next_server/auth-x.php?auth_user=1");
    curl_setopt($ch, CURLOPT_POST, 1);
    curl_setopt($ch, CURLOPT_POSTFIELDS, "user_name=$_SESSION[user_name]&user_pass=$_SESSION[user_pass]&auth_user=1");
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    $sid=curl_exec ($ch);
    curl_close ($ch);
    if(preg_match("!<PHPSESSID>(.*?)</PHPSESSID>!si", $sid ,$sid)) $sid=$sid[1];
    else $sid='';
     //xdump($_SESSION);
     //xdump("Location: ".urldecode($_GET['url_from'])."?$sid", 1);//exit;
    header("Location: ".urldecode($_GET['url_from'])."?$sid");exit;
 }/**/
/*Проверка даных пришедших из формы
*если авторизировался, отправляем обратно с SID
*/
  if ($_POST['user_name']=='demo' && $_POST['user_pass']=='post'){
    $_SESSION['authorized']=1;
    $_SESSION['user_name']=$_POST['user_name'];
    $_SESSION['user_pass']=$_POST['user_pass'];
    $_SESSION['domain']='test';
  if (defined("SID") AND constant("SID")) $sid='?'.SID; else $sid='';
  if(!empty($_POST['auth_user'])){ echo '<PHPSESSID>'.SID.'</PHPSESSID>';exit;}
  header("Location: ".urldecode($_GET['url_from']).$sid);exit;
}else $_SESSION['authorized']=NULL?>
<!--kpss7-->
<H2>Avtorize panel</H2>
<form action="<?=getenv($_GET['url_from'])?>" method="POST">
Name: <input name="user_name" type="text" length="10"><br>
Pass: <input name="user_pass" type="text" length="10"><br>
<input name="submit" type="submit" value="Login">
</form>
<font size="2">
Внимание если форма не опознала Вас,<br> авторизируйтесь:
<a href="auth-serv.php?url_from=<?=$_GET['url_from']?>">Авторизация</a></font>
sec-x.php ->
PHP:
<?include_once($_SERVER['DOCUMENT_ROOT'].'/lib/uses.phl'); uses('dump');?>
<?if(!empty($_GET['PHPSESSID'])) session_id($_GET['PHPSESSID']);?>
<?session_start();
 $preview_server='127.0.0.8';
 $current_server='127.0.0.7';
 $next_server='127.0.0.8';

/*А проверка регистрации и/или если поьзователь пришел с
 * нашего сайта, отсылаем обратно за ID сессии
*/
 if (empty($_SESSION['authorized'])) {
   if(strpos($_SERVER['HTTP_REFERER'], $preview_server)!==false&&empty($_SESSION['come_back'])){
     $_SESSION['come_back']=1;
     header("Location: http://$preview_server/auth-x.php?url_from=".urlencode("http://$current_server/sec-x.php"));
     exit;
   }
   else{
     header('Location: auth-x.php?url_from='.urlencode("http://$current_server/sec-x.php"));
     exit;
   }
 }
?>
<!--kpss7-->
<?xdump($_SERVER, 1);
  xdump("The kpss7", 1);?>
<a href=http://127.0.0.8/sec-x.php>dsf</a>
Тестил вроде работает.
Плюсы:
распрделенная система нет центрального сервера
полное разделение сайтов по правам доступа
между собой внутри системы
если все загнать в https будет еще и безопасно
Минусы:
возможна перегрузка сервера
требуется статистическая обработа преходов
и коректирование алгоритмов
сильно зависит от быстродействия как текущего
сервара так и с того с которого пришел пользователь
 

NEK

Guest
auth-serv.php ->
PHP:
<?session_start()?>
<?include_once($_SERVER['DOCUMENT_ROOT'].'/lib/uses.phl');uses('dump');?>
<?
/*Если мы тут были и вернулись обратно - неавторизованы
 *Если с текущего сервера - перенапавляем на следующий
 *Если авторизированы тут - авторизизируемся на сервере с которого пришел запрос
 */
 $preview_server='127.0.0.8';
 $current_server='127.0.0.7';
 $next_server='127.0.0.8';

 if(!empty($_SESSION['come_back'])){
   $_SESSION['come_back']=NULL;
   header("Location: http://$current_server/auth-x.php?url_from=$_GET[url_from]");
   exit;
 }
 if(strpos($_GET['url_from'], $current_server)!==false){
   $_SESSION['come_back']=1;
   header("Location: http://$next_server/auth-serv.php?url_from=$_GET[url_from]"); exit;}
 if(!empty($_SESSION['authorized'])){
   $ch = curl_init();
   curl_setopt($ch, CURLOPT_URL, "http://$next_server/auth-x.php?auth_user=1");
   curl_setopt($ch, CURLOPT_POST, 1);
   curl_setopt($ch, CURLOPT_POSTFIELDS, "user_name=$_SESSION[user_name]&user_pass=$_SESSION[user_pass]&auth_user=1");
   curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
   $sid=curl_exec ($ch);
   curl_close ($ch);
   if(preg_match("!<PHPSESSID>(.*?)</PHPSESSID>!si", $sid ,$sid)) $sid=$sid[1];
   else $sid='';
   //xdump("Location: ".urldecode($_GET['url_from'])."?$sid", 1);
   //xdump($_SESSION, 1);exit;
   header("Location: ".urldecode($_GET['url_from'])."?$sid");exit;
 }
?>
 

NEK

Guest
Автор оригинала: Фанат
что это было, папа?
Да вроде как работающая штука, правда без https, -
грошь цена ей.

Работает просто
1) Регистрируемся
2) Если по ссылке пришли со своего сервара =>
отсылаем обратно, тогда если там пользователь
зарегестрирован => посыем логин пасс на
регистрацию , если успешно => в ответ session_id,
приклеиваем откуда пришел пользователь и
отсылаем обрано, иначе на форму регистрации.
3) Если на одном сайте авторизирован, и
пользователь в новом окне открывает один из ХХХ
сайтов видит форму.
Скрипт auth-serv.php поочередно пересылает
пользователя с одного (нашего) сервера на другой
пытаясь найти на каком он авторизован , если
возвращается назад или нигде не авторизирован
=> форма, иначе посылка логин / пасс в случае
успеха session_id

Да надо, что-бы между окнами браузера был общий доступ к кукам (тестил Opera, Mozilla, IE 6.0 подкачал)
 

rozhik

Guest
После ауторизации сид кидать на центральный сервер через CURL.
Зачем выдумывать колесо. При пересылке на другой домен добавлять в GET параметр с SID.
Когда приходит на сайт зверь с SID в параметре - делаем запрос центрального для проверки SID, и записываем в свою сессию (естественно сообщаем о этом центральному серверу).
Механизм используется в t-mobile и не только.
 

Sparrow

Новичок
А не проще ли использовать авторизацию через mysql. В одной таблице хранить данные по юзерам (поля username, password (зашифрованный) и.т.п., в другой - session_id, user_name,last_access. После авторизации session_id передается в куку, а при переходе на другой сайт, принадлежащий community - через GET. Базу сессий можно сделать типа HEAP, или поставить garbage cleaner по тому же принципу, что и в сессиях php. Единственный недостаток этого метода - все сервера должны быть на одной машине.
 
Статус
В этой теме нельзя размещать новые ответы.
Сверху