Как можно управлять разрешениями пользователей на определенные данные в Backpack для Laravel?

#laravel #laravel-backpack

#ларавель #laravel-рюкзак #laravel #laravel-backpack

Вопрос:

Я использую laravel-backpack admin для раздела администрирования моего приложения, а также я использую PermissionManager для управления ролями и разрешениями пользователей. Теперь я хочу назначить конкретный доступ к конкретным данным.

например, представьте, что у нас есть система управления статьями, а также у нас есть editor роль и связанные с ней разрешения для пользователя, имя пользователя которого user24 , поэтому желаемый способ заключается в том user24 , чтобы получить доступ к определенным статьям, например article 1 , в их панели мониторинга или списке crud.

Articles структура таблицы:

ПРИМЕЧАНИЕ: поле ‘user_id’ указывает на владельца статьи.

 |---------------------|------------------|------------------|   
|      id             |     title        |     user_id      |
|---------------------|------------------|------------------|
|          1          |     article1     |        2         |
|---------------------|------------------|------------------|
  

Ответ №1:

Подход 1:

Один из способов добиться этого — создать второй класс с именем CrudArticle (или что-то еще), расширить исходный класс Article, но затем добавить глобальную область видимости к этой модели, которая ограничивает все запросы к таблице с использованием класса, включая только записи, принадлежащие текущему пользователю. Используйте этот класс с вашей панелью CRUD и классом normal Articles в другом месте вашего приложения.

 class CrudArticle extends Article {

    public static function boot()
    {
        parent::boot();
        
        // only include models that belong to this user
        $user_id = 0;
        Auth::check();
        if ($user = Auth::user()) {
            $user_id = $user->id;
        }
        static::addGlobalScope('userFilter', static function (Builder $builder) use ($user_id){
            $builder->where('user_id', $user_id);
        });
    }
}
  

ПРИМЕЧАНИЕ: Это предотвратит появление записей, не принадлежащих пользователю, на странице списка и предотвратит загрузку страницы редактирования по прямому URL. Однако я не уверен на 100%, что только вышеуказанное защитит от вставок (запросов post непосредственно к конечной точке обновления), т. Е. Вам все равно может потребоваться изменение для «UpdateRequest», рекомендованного во втором возможном решении ниже


Подход 2:

Другой способ добиться этого — изменить запросы, используемые CRUD, например, в вашем контроллере CRUD:

 /**
 * Set up the "list" or "read" operation for the resource
 */
public function setupListOperation(): void
{
    // ... normal setup code ...

    Auth::check();
    $user = Auth::user();
    if (!$user) {
        throw new Exception('Unauthorized');
    }
    $this->crud->query = $this->crud->query->where('user_id', $user->id);
}
  

Чтобы предотвратить просмотр страницы обновления через прямой URL, вы можете добавить что-то вроде этого в setupUpdateOperation:

 /**
 * Set up the "update" operation for the resource
 */
public function setupUpdateOperation(): void
{
    // ... normal setup code ...
    
    $authorized = false;
    // only allow viewing the update page if the user is logged in and owns the Article
    Auth::check();
    if ($user = Auth::user()) {
        $id = $this->get('id');
        $product = Article::find($id);
        if ($product) {
            $authorized = $product->user_id === $user->id;
        }
    }
    if (!$authorized) {
        $this->crud->denyAccess(['update']);
    }
}
  

Чтобы предотвратить несанкционированное редактирование, отправленное непосредственно в конечную точку обновления, вам также необходимо добавить что-то вроде приведенного ниже в свой UpdateRequest:

 /**
 * Determine if the user is authorized to make this request.
 *
 * @return bool
 */
public function authorize()
{
    $authorized = false;
    // only allow updates if the user is logged in and owns the Article
    Auth::check();
    if ($user = Auth::user()) {
        $id = $this->get('id');
        $product = Article::find($id);
        if ($product) {
            $authorized = $product->user_id === $user->id;
        }
    }
    return $authorized;
}
  

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

Комментарии:

1. Спасибо за ваш ответ, но упомянутое user_id поле относится к владельцу статьи, поэтому я хочу назначить доступ другим пользователям, которые не являются владельцем статьи.

2. @MeysamZarei Хм, я не уверен, что понимаю, как там используется, однако применяется тот же принцип, вы просто измените условия на те, которые вам нужны.

3. Вы правы. Я искал библиотеку или что-то еще для этого, чтобы сделать это хорошо, но я ничего не нашел. Итак, как вы сказали, это кажется подходящим принципом, и мне кажется, что я должен справиться с упомянутой проблемой.