Русское сообщество разработки на PHP-фреймворке Laravel.
Ты не вошёл. Вход тут.
Страницы 1
Всем привет!
Такой вопрос назрел - делаю систему авторизации. У меня есть несколько ролей, среди них админ. Мне нужно чтобы я от админа мог зайти под любым другим пользователем и выйти соотвественно. Если бы я использовал обычные сессии, то задача решается установкой id залогиненного юзера, и id админа (чтобы вернуться обратно). Но я пытаюсь использовать те средства что предоставляет laravel, и не очень понимаю как грамотно все сделать.
Во-первых у меня щас стоит время жизни сессии 0, т.е. по закрытию браузера сессия обнуляется.
Во-вторых у меня есть галка типа "Запомнить меня", $remember = true то бишь.
Одновременно писать
Auth::logout();
Auth::login(User::find($id));
нельзя, ругается с ошибкой.
Без logout-а вроде сработало, но если я проставлю Session::put('logged_from_admin', true) то после закрытия браузера я уже потеряю эту переменную. Можно убрать нулевое время, но тогда смысл в галке "Запомнить меня"
И я не очень понял разницу между login и loginUsingId (разве что один принимает модель, другой айдишник). С помощью второй ф-ии залогиниться не получилось вообще
Не в сети
Не в сети
А что туда записать, типа logged_from_admin = true, admin_id = ... ?
И сделать кнопку если есть такая кука, по кнопке переходим на ф-ию где проверка опять же наличия куки, и если она есть - релогин из под admin_id?
Просто не хорошо же хранить такие данные в куках?
Да, laravel 4
Не в сети
Какая у тебя стоит задача? Админ зашёл на сайт, авторизовался как он сам, поставив флаг «Запомнить меня». Затем авторизовался как другой пользователь. Как ты хочешь сделать — чтобы админ при выходе снова стал собой или он стал обычным пользователем и может выйти, а затем снова зайти под своим паролем?
Не в сети
Админ зашел на сайт, авторизовался (либо с галочкой "запомнить меня" либо без неё, как решит). Ему вывелся список пользователей и рядом с каждым юзером иконка "войти от юзера". После того как он кликнул, он залогинелся от имени этого юзера и видит его админку + кнопку "вернуться назад от админа" по нажатию на которую он становится админом.
logged_from_admin чтобы отобразить кнопку. Ну можно без неё, просто проверять есть ли admin_id. Только меня смущает класть это в куки.
Не в сети
"чтобы админ при выходе снова стал собой" - да, вот так
Не в сети
Имхо, вы как-то не с той стороны заходите, у вас ролевая система - сделайте что-то вроде
if ( $role === 'admin' ){
//грузим необходимые данные пользователя
}
может я как-то не так понял, но авторизация нужна чтобы отделять одного пользователя от другого, отделять их роли, а не смешивать.
А еще это не этично))
Не в сети
Потом звонит юзер и говорит "у меня что-то в админке цифры не те, можете посмотреть?", а я ему: "не, не могу, дайте пароль"
Не в сети
if ( $role === 'admin' ){
//грузим админку пользователя
//???
//PROFIT!!
}
Не в сети
У меня есть admin, есть client. У них разные админки. У каждого свой логин и пароль. Клиентов много, админ один.
If ($role =='admin') { грузим админку админа; }
if ($role == 'client') { грузим админку клиента; }
Но админ должен иметь возможность увидеть админку глазами клиента
Не в сети
function get_clientadminka ( $idclient ){
$data = Client::adminka($idclient );
return View::make( 'client.adminka' )->with( 'data', $data );
}
Не в сети
Etern1ty прав и такая проблема/usecase действительно есть. Наглядный пример — интернет-магазин, где есть админы (я), менеджеры и пользователи. Менеджеры видят список своих заказов, пользователи — своих, я как админ вижу их все. Возможности переключаться между видами нет. Зато есть возможность входа под любым пользователем, если это позволяют права — и это очень удобно, не нужно придумывать переключатели «смотреть как админ/пользователь» для каждой функции — один «sudo» покрывает их все.
Касательно сабжа. Раз у тебя сессия закрывается вместе с браузером логичнее всего использовать долгоживущую cookie, но вместо пароля или ещё какой-то закрытой информации хранить там ID админа (который стал пользователем) и хэшировать (подписывать) его твоим application.key. На самом деле Laravel (3 точно) уже сам подписывает cookie — открой Firebug и посмотри, любая cookie будет содержать перед своим значением строку с хэшем:
language = 9e237a356c34b1fa243e30b25bf92757422de286~ru
Если попытаешься изменить значение напрямую хэш не совпадёт и Laravel удалит её. Таким образом можешь хранить ID в открытую, не беспокоясь, что кто-то установит cookie — ему для этого нужно будет знать твой ключ. Для верности, чтобы хэш постоянно менялся, можешь добавлять второй хэш, зависящей от номера недели и года, к примеру — тогда человек не сможет подсмотреть хэш у вошедшего админа и использовать его у себя.
Не в сети
// Главная. Проверяем залогинен ли юзер
Route::get('/', function() {
if (Auth::check())
$user = Auth::user();
// Если админ
if (Company::isSuperAdmin($user->company_id)) {
// Достать юзеров которые не админы
$users = User::join('settings', 'settings.value', '!=', 'users.company_id')
->where('settings.name', '=', 'admin_id')
->get();
return View::make('admin')->with('users', $users);
} else {
// Если не админ то передаем куку sudoer. Если она есть, выводим ссылку "Вернутся к админу"
return View::make('client')->with('sudoer', Cookie::get('sudoer'))
->with('email', $user->email);
}
} else {
return View::make('login');
}
});
Route::get('logout', function() {
Auth::logout();
// Если есть кука то удалить её (-1 время жизни)
if (Cookie::get('sudoer')) {
$sudoer = Cookie::make('sudoer', false, -1);
return Redirect::to('/')->withCookie($sudoer);
} else {
return Redirect::to('/');
}
});
// Логинемся от админа под другим юзером
Route::get('loginAsUser/{id}', array('before' => 'superAdminJSON', function($id) {
$sudoer = Cookie::make('sudoer', Auth::user()->id); // Кука с айди админа
Auth::login(User::find($id));
return Redirect::back()->withCookie($sudoer);
}));
// Возвращаемся в админку из под админа
Route::get('returnToAdmin', function() {
if (Cookie::get('sudoer')) {
Auth::login(User::find(Cookie::get('sudoer')));
return Redirect::back()->withCookie(Cookie::make('sudoer', false, -1)); // Удаляем куку
}
});
Я правильно понимаю что главное в куках это то что юзер не может ничего поменять, но если их типа украдут с компа то их можно будет использовать? Я попробовал в двух браузерах вручную скопировать содержимое кук и все сработало, но можно же приписывать user agent, айпи и т.п. внутри содержимого и тогда даже если её украсть нельзя будет её использовать ? (Ну, понятно что можно все подделать, но при этом айпи например нам неизвестен еже)
Изменено Etern1ty (13.06.2013 12:57:18)
Не в сети
- но если их типа украдут с компа то их можно будет использовать?
- (Ну, понятно что можно все подделать, но при этом айпи например нам неизвестен еже)
Для этого я предложил добавлять какой-то переменный признак типа дня недели — даже если кто-то узнает всё, то через некоторое время его доступ всё равно закроется, так как он не сможет перегенерировать хэш.
Ещё лучше — не просто хранить эту переменную информацию в открытую, а тоже хэшировать, чтобы никто без исходников не мог узнать, как именно составляется такая строка и что в неё входит (IP, дата и т.п.) — это мне кажется самым надёжным вариантом.
Не в сети
А в laravel 4 я как вижу и так значения не хранятся в открытом виде:
sudoer = eyJpdiI6IjJsXC80aDQ5d3V4NE9aSlBmRDFxTjhySHJzUDQ5dzlsY0xJaGV4aDdoUDBRPSIsInZhbHVlIjoiXC9hVW5ybFRibUJUaHpHTXBuV0pKR1kzVDU2TW8zNmZKWEEwYkd3YURaaVU9IiwibWFjIjoiNjBlNTQ5MjdmOGZmNTFlM2M5NzRjN2I5Mjc4YWI5ZWJiZWFmYWJiY2U2NDE1NzkxODFjZGRjMjg0OTcwMGQ0MyJ9
Но если её в таком виде украсть то у юзера появится кнопочка «Зайти обратно к админу».
Я не очень понял насчет добавления даты. Т.е. например я сейчас кладу PHPCookie::make('sudoer', Auth::user()->id)
типа айдишник админа. Ты предлагаешь класть что то вроде
Cookie::make('sudoer', array('created_at' => time(), 'expires_at' => time() + 60*60*24*7, 'admin_id' => $id);
И дальше когда достаешь куку проверять не сдохла ли она по времени и если да то регенерировать? Или как?)
Еще вопрос по терминологии — когда мы говорим о хешировании куки, подразумевается шифрование, т.е. там не md5 какой-нибудь, иначе мы бы не смогли достать данные из кук — верно? Используется именно шифрование по app.key
Изменено Etern1ty (13.06.2013 15:47:25)
Не в сети
- А в laravel 4 я как вижу и так значения не хранятся в открытом виде:
Может быть в L4, с ней не работал.
- когда мы говорим о хешировании куки, подразумевается шифрование, т.е. там не md5 какой-нибудь
Как раз-таки хэширование, а не шифрование (двухстороннее). Всё проще: устанавливаешь cookie не PHP$id
, а PHP$id.'-'.date('W')
. В результате каждые 7 дней хэш будет меняться даже для одного и того же пользователя.
Не в сети
Если хеширование, то как мы можем получить в принципе значение кук, хеш на то и хеш что мы можем только сверить значение (юзер ввел пароль, мы его захешировали и сравнили хеш. а в куках мы напрямую получаем значение Cookie::get)
Вообще опять не понятно. Почему это должно помочь. Вот например, у юзера в куках лежит какая-то цифра, типа количество раз сколько он зашел на сайт. Я эту куку ворую, и у меня на сайте отображается та же инфа. Потом юзер (у кого я своровал) заходит еще раз, и цифра увеличивается. Но почему у меня должно пропасть значение которогое я своровал?
Я попробовал открыть 2 браузера, залогинется от имени юзера на одном, потом копирнул куки на другой. Вижу два одинаковых экрана. Потом на первом браузере разлогиневаюсь, прибавляю к куки рандом Cookie::make(’sudoer’, $id.’123123213’), залогиневаюсь обратно. Вижу тот же экран. И жму на обоих экранах «Вернутся к администратору» (по этой ссылке я просто вывожу значение айдишника админа). На одном я вижу айдишник админа, на другом айдишник админа + рандом. И там и там кука работает, просто лежит в ней разное
Не в сети
Принцип действия тот же, что и с хранением хэшей паролей вместо самих паролей. Если в cookie (без шифрования/подписывания Laravel, рассматриваем просто PHP) хранить любое значение, то его можно изменить и сервер об этом не узнает. В то же время, если там хранить то же самое значение плюс: PHP'~'.md5($value.'-random_string...-'.date('W'))
— таким образом строка (значение cookie, видимое клиенту) будет значение~подпись-32-символа — при попытке изменить значение (часть до тильды) хэш (часть после тильды) перестанет совпадать. То есть при каждом считывании cookie сервер разделяет строку на значение и хэш, вычисляет хэш для строки и если он не совпадает с переданным — cookie менялась без ведома сервера, так как он бы подписал её верным хэшем, алгоритм вычисления которого он знает.
Добавляя переменный элемент типа номера недели в году мы получаем новый хэш каждые 7 дней. Добавить случайную строку сюда не получится, так как ты сам не сможешь проверить подпись при следующей загрузке страницы.
Не в сети
А, ну первый абзац я понял, да. Просто laravel 4 хранит куки не в виде «хеш~значение», я привел выше пример. Поэтому делаю вывод что куки хранятся в шифрованном а не хешированном виде (http://laravel.com/docs/security#encryption случаем не так?).
В моем случае получается я храню значение айдишника админа в виде: admin_id~date(’W’). Это значение лежит в зашифрованном виде (в любом случае его в фаербаге не видно никак, только рандомный набор символов). После этого, когда я получаю куку я разбиваю по тильде и смотрю день недели. Если он не равен текущем то куа не действительна?
// Супер админ может залогинется от другого юзера
Route::group(array('before' => 'superAdminJSON'), function() {
Route::get('loginAsUser/{id}', function($id) {
$sudoer = Cookie::make('sudoer', Auth::user()->id.'~'.date('W')); // Кука с днем недели
Auth::login(User::find($id));
return Redirect::back()->withCookie($sudoer);
});
});
// .... Генерация вьюшки для обычного клиента
if (!Cookie::has('sudoer')) { // Если куки нет то нет
$sudoer = false;
} else {
$cookie = explode('~', Cookie::get('sudoer')); // Если кука есть то разбиваем по тильде
$sudoer = $cookie[1] === date('W') ? true : false; // Если неделя сегодняшняя то тру, иначе фолс
}
return View::make('client')->with('sudoer', $sudoer)
->with('email', $user->email);
Не в сети
- (http://laravel.com/docs/security#encryption случаем не так?).
Если так то да, это двухстороннее шифрование и оно будет одинаковым для любого клиента.
- Если он не равен текущем то куа не действительна?
Да, ты фактически делаешь то, что делает L3.
Пример неверный с точки зрения хэша — ты ведь его нигде не вычисляешь, а просто сохраняешь номер недели. Другое дело, что если cookie шифруется, то можно не добавлять ещё и хэш, а просто добавлять случайное число (то, что я говорил в предыдущем посте предполагало, что у тебя строка хранится в открытом виде, как в L3). Это будет даже лучше, так как даже у одного пользователя в один и тот же день при входе/выходе cookie будет иметь разный вид.
Не в сети
Да, с точки зрения хеша md5(date(’W’)), ок.
Но про рандомную строку вовсе не понял: какой вид должна в итоге иметь кука? айди_админа~рандомная_строка?
У нас цель чтобы кука стала не действительна через какое то время после того как её украли. Хранится она в шифрованном виде.
Какую мне рандомную строку добавлять чтобы понять что через какой-то срок она не действительна? В случае с неделями я сравниваю номер недели.
Да, при генерации куки с md5(microtime()) (рандомная строка) при входе каждый раз разная кука, ну и что, если я её скопирую себе то она будет действительна, и я залогинюсь от админа
Не в сети
Товарищи знатоки - У меня такое предложение - а что если при каждом запросе генерировать новый ID сессий? - с пмощью функции
session_regenerate_id(); - Я пробовал - но вот только захешировать не получется! - т.к. session_regenerate_id(true); работает после session_start();
а session_id(); в котором можно задавать имя ID до - но я нашел всего 1 способ - это повторно отправить кукки с помощью функции setcookie(); НО это двойная работа - есть другие идеи?
Не в сети
}%А чем не нравится подход с хэшем? По-моему проще некуда.
Ты не понял у меня стоит session_regenerate_id() гекоторый генерирует PHPSESSID (кукки) ПРИ КАЖДОМ ЗАПРОСЕ но я не могу его захешировать не получается - т.к. он работае только после session_start()! а session_id(здесь уникальный ID в MD5) наоборот работает только до session_start()! единственый способ который я нашол - это перезаписать кукки с помощью функции setcookie() - может знает кто как захешировать без использования функции setcookie()?
На самом деле кто мешает зайти за админа, и из него залогиниться под другого пользователя. А из этого пользователя уже можно просто выйти, и войти с паролем и логином под админам. Это безопаснее по любому. А второй вариант дать логиниться только из под определенных IP, юзерам с правами админа. Все же куда ни цепляй куку, ее можно стащить, а это потеря безопасности.
Да и плюс к этому, хорошо делать так, что бы к юзеру с админ правами другой не мог зайти (по мне это хороший тон).
Изменено Ruzarh (24.03.2014 13:22:41)
Не в сети
Страницы 1