Защита роутов через middleware или что-то другое

118
22 января 2021, 04:20

Имею следующую схему данных

  • Users. Таблица с данными пользователей
  • Journals. Таблица со списком журналов.
  • Entries. Таблица со списком записей в журналах.
  • journal_user. Журнал могут вести разные пользователи. Таблица описывает права. Только те пользователи, которым указаны в этой таблице для определённого журнала, могут его вести.
  • Связь от Users к Entries. Каждая запись в журнале принадлежит определённому пользователю.

Есть Journal, который могут заполнять Entries определённые Users. Каждая Entry принадлежит определённому User. И только пользователь, который сделал эту Entry может её редактировать. Имеется необходимость в следующих ограничениях:

  • Для определённого Journal только определённые Users могут оставлять Entries. Остальные Users не должны иметь никаких прав на работу с Journals и Entries.
  • Только тот User, который оставил Entry (при условии, что он всё ещё имеет права на работу с журналом, т.е. присутствует в таблице journal_user) может редактировать её. Остальные доверенные пользователи (из таблицы journal_user для текущего Journal) могут только читать.

Я не знаю, как подступиться к описанным выше требованиям к ограничениям. Самое удобное - сделать ограничение подобное на стороне middleware, который бы использовался в качестве middleware для группы роутов в web.php. И если с пользователем понятно (я могу получить его данные через Auth::user()), то как быть с Journal?

Route::get('journals/{journal}', 'JournalController@show')->name('journals.show');

Нужно проверить, что пользователь может открыть этот журнал. Значит на стороне middleware нужно как-то получить переданный параметр роута {journal}. Как это можно сделать?

Насчёт возможности редактирования только своей записи я вроде бы понимаю - реализовать можно через Request и валидацию (есть там метод auth). Но как быть с выше описанным? Это можно сделать как-то иначе? Да, я могу в каждом методе контроллеров проверять, но это же не правильно, да?

Answer 1

Как создать посредника маршрута в Laravel описано здесь middleware. Все действия сводятся к двум простым шагам - создание файла посредника и его последующая регистрация. Назначим на маршрут наш посредник:

Route::get('journals/{journal}', 'JournalController@show')
  ->name('journals.show')
  ->middleware('journal.control');

Код посредника:

use App\Models\JournalUsers;
class JournalControl
{
  public function handle($request, Closure $next)
  {
    $journal = $request->route('journal');
    if($this->checkJournalRight($journal) {
      return $next($request);
    }
    return abort(404);
  }
  public function checkJournalRight($journal_id)
  {
    if(
      JournalUsers::where('user_id', session()->get('user_id'))
        ->where('journal_id', $journal_id)
        ->first()
    ) {
      return true;
    }
    return false;
}

Все легко и просто, в первом действии извлекаем параметр journal с маршрута, и ищем в таблице права пользователя на указанный журнал.

Теперь о записях в журнале(предполагаю что это отдельная сущность в виде таблицы, где есть ключ на journal_id и создателя user_id).

use App\Models\Entries;
public function checkRight()
{
  $right = Entries::where('user_id', session()->get('user_id'))
    ->where('journal_id', $request->route('journal'))
    ->where('id', $request->route('entry'))
    ->first();
  return (!empty($right)) ? true : false;
}

Использовать код в посреднике или контролере решать Вам. Код маршрута может выглядеть примерно так:

Route::get('journals/{journal}/entries/{entry}');

PS. Код написан на чистом энтузиазме. Я никогда не использовал стандартную регистрацию Laravel. Используйте свои данные вместо моих.

READ ALSO
Обсчитать данные времени, php

Обсчитать данные времени, php

Всем доброго времени сутокВозник вопрос, как мне от текущего времени отнять время из бд? У меня есть табличка с типом Time, там пока около 20 записей,...

73
Отправить файл с помощью cURL

Отправить файл с помощью cURL

Скопировал код из мануала

110
Инъекции в куки

Инъекции в куки

Пишу свой велосипед, который будет из себя представлять менеджер паролей для входа на сайты (да, знаю, что в браузерах есть куча готовых решений,...

89