• Время чтения ~3 мин
  • 29.03.2023

При использовании Laravel Jetstream Teams роли Jetstream по умолчанию могут быть непреклонными для некоторые потребности. Когда вам нужны дополнительные функции, связанные с управлением ролями вашей команды, вы можете объединить Laravel Jetstream с популярный пакет разрешений Spatie.

Приступая к работе

, я предполагаю, что у вас есть новая установка Laravel Jetstream с включенной функцией teams, если вы не знаете, как это сделать пожалуйста, следуйте документации Laravel Jetstream.

В этом примере я использую стек Livewire, но поскольку я фокусируюсь на серверных вещах, этот учебник должен одинаково работать со стеком инерции.

Установка пакета

разрешений Spatie Мы начинаем установку пакета через composer.

composer require spatie/laravel-permission

Теперь мы публикуем миграцию и конфигурационный файл разрешения.php с:

php artisan vendor:publish --provider="Spatie\Permission\PermissionServiceProvider"

Теперь добавьте атрибут Spatie Permission HasRoles в вашу пользовательскую модель.

use Spatie\Permission\Traits\HasRoles;

class User extends Authenticatable
{
    use HasApiTokens;
    use HasFactory;
    use HasProfilePhoto;
    use HasTeams;
    use Notifiable;
    use TwoFactorAuthenticatable;
    use HasRoles;
}

Теперь нам нужно включить функцию разрешений команды. В основном мы следим документация Spatie с некоторыми Настройка Jetstream.

Включите конфигурацию разрешений teams:

// config/permission.php
'teams' => true,

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

php artisan make:middleware TeamsPermission

В промежуточном ПО TeamsPermission мы должны извлечь текущий идентификатор команды пользователей и применить его к разрешениям Spatie Сфера охвата команды.

use Closure;
use Illuminate\Http\Request;
use Spatie\Permission\PermissionRegistrar;

class TeamsPermission
{
    public function handle(Request $request, Closure $next)
    {
        if (!empty($user = auth()->user()) && !empty($user->current_team_id)) {
            app(PermissionRegistrar::class)->setPermissionsTeamId($user->current_team_id);
        }

        return $next($request);
    }
}

Это промежуточное ПО должно применяться к каждому HTTP-запросу, поступающему в наше приложение. Для этого мы должны расширить Файл ядра.php.

        //app/Http/Kernel.php
        'web' => [
            ...
            \App\Http\Middleware\TeamsPermission::class
        ],

В моем случае я не хочу, чтобы это промежуточное ПО применялось к запросам API, поэтому я добавил его только в группу промежуточного ПО «веб». Если вы хотите, чтобы он применялся ко всем запросам, вы можете добавить его в глобальный стек промежуточного ПО.

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

Настройка сидеров для демонстрационных данных

Чтобы поиграть с нашей новой кодовой базой, нам понадобятся некоторые демонстрационные данные. Давайте установим несколько быстрых и грязных сеялок.

php artisan make:seeder PermissionSeeder

Начальные роли и разрешения

//Database\Seeders\PermissionSeeder.php

namespace Database\Seeders;

use Illuminate\Database\Seeder;
use Spatie\Permission\Models\Permission;
use Spatie\Permission\Models\Role;

class PermissionSeeder extends Seeder
{
    public function run(): void
    {
        //Some initially role configuration
        $roles = [
            'Admin' => [
                'view posts',
                'create posts',
                'update posts',
                'delete posts',
            ],
            'Editor' => [
                'view posts',
                'create posts',
                'update posts'
            ],
            'Member' => [
                'view posts'
            ]
        ];

        collect($roles)->each(function ($permissions, $role) {
            $role = Role::findOrCreate($role);
            collect($permissions)->each(function ($permission) use ($role) {
                $role->permissions()->save(Permission::findOrCreate($permission));
            });
        });
    }
}

Начальный демонстрационный пользователь с личным и 3 другими связанными членствами в командах Управление ролями

//Database\Seeders\DatabaseSeeder.php
namespace Database\Seeders;

use App\Models\Team;
use App\Models\User;
use Illuminate\Database\Seeder;

class DatabaseSeeder extends Seeder
{
    public function run(): void
    {
        $this->call([PermissionSeeder::class]);

        User::factory(['email' => '[email protected]'])
            ->withPersonalTeam()
            ->hasAttached(Team::factory()->count(3))
            ->create();

    }
}

во фронтенде

Я предполагаю, что вы хотите показать текущим ролям пользователей во фронтенде, и вы хотите иметь своего рода пользователей администратора, которые могут управлять ролями членов команды. Поскольку кодовая база Jetstream изменится в будущем, мы не будем расширять код по умолчанию Jetstream управляет ролями / действиями членства в команде для этого.

Поэтому я приведу несколько примеров кода, как использовать несколько ролей в командах Jetstream.

Поскольку каждый фронтенд-запрос, поступающий в наше приложение, обслуживается через наше \App\Http\Middleware\TeamsPermission:: промежуточное ПО класса Пакет разрешений Spatie всегда знает о текущей области группы пользователей. Таким образом, каждая роль или Запрос разрешения, который был вызван во внешнем интерфейсе, ограничен текущим идентификатором команды пользователей.

Таким образом, мы можем использовать пакет разрешений Spatie, как мы обычно это делаем. Все работает как положено!

//Get the user roles
auth()->user->roles()->get();
//Get the user permissions
auth()->user->permissions()->get();
//Give permission to a user
$role->givePermissionTo($permission);
//assign Roles
$permission->assignRole($role);

Управление ролями для КАЖДОГО API / Backend

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

Для этого нам нужен вызывающий контроллер API, который может обновлять команды.

php artisan make:controller Api/UpdateTeamController -i

Для простоты мы не будем создавать классы Request и Resource для этого примера.

namespace App\Http\Controllers\Api;

use App\Http\Controllers\Controller;
use App\Models\Team;
use App\Models\User;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Validation\Rule;
use Spatie\Permission\PermissionRegistrar;

class UpdateTeamController extends Controller
{
    public function __invoke(Request $request, Team $team): Team
    {
        $data = $request->validate([
            'name' => ['string', 'required', 'max:255'],
            'memberships' => ['array', 'sometimes'],
            'memberships.*.user_id' => ['required', 'integer', 'exists:users,id'],
            'memberships.*.roles' => ['present', 'array'],
            'memberships.*.roles.*' => ['string', Rule::exists('roles', 'name')->where('guard_name', 'web')]
        ]);

        DB::transaction(function () use (&$team, $data, $request) {
            //Update team fields
            $team->forceFill($request->except(['memberships']));
            $team->saveOrFail();

            if ($request->has('memberships')) {
                $memberships = collect($data['memberships']);
                //sync team memberships
                $team->users()->sync($memberships->map(function ($membership) {
                    return $membership['user_id'];
                })->toArray());
                //set Spatie permissions team foreign id scope
                app(PermissionRegistrar::class)->setPermissionsTeamId($team->id);
                //sync roles
                $memberships->each(function ($membership) {
                    $user = User::findOrFail($membership['user_id']);
                    $user->syncRoles($membership['roles']);
                });
            }

        });
        return $team;
    }
}

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

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

Когда DB::transaction() каждый запрос к базе данных, выполняемый в пределах закрытия, упаковывается в фиксацию базы данных. Если при закрытии возникает исключение, Laravel Framework откатывает все наши изменения. Когда все идет хорошо, это автоматически фиксирует наши изменения в базе данных.

В рамках транзакции мы начинаем обновлять поля команды. Ничего особенного в этом нет. После этого мы обрабатываем поля из массива memberships. Сначала мы начинаем синхронизацию всех предоставленных идентификаторов пользователей с Команда Jetstream, использующая метод sync() в отношении членства belongsToMany().

Теперь мы переходим к конкретным материалам Spatie Laravel Permission:

Сначала мы должны сообщить пакету разрешений, в какой области Team мы находимся app(PermissionRegistrar::class)->setPermissionsTeamId($team->id);. Таким образом, все разрешения или роли, которые обновляются или выбираются после этой строки кода, всегда ограничены текущей командой Jetstream. В этом случае мы хотим, чтобы это была конкретная команда, предоставляемая для каждой модели привязки маршрута к нашему контроллеру. Но иногда вы хотите обновить разрешения для разных команд в цикле, тогда вам нужно установить эту область каждый раз. при изменении соответствующей области команды.

После изменения области действия команды мы можем обновить роли, как мы обычно это делаем.

В конце нашего действия контроллера мы возвращаем обновленный объект Team.

Заключительные слова

Мы узнали, как объединить команды Laravel Jetstream с потрясающим пакетом Spatie Permission. Благодаря потрясающей документации из этих пакетов мы в основном следуем официальным Документам. Но я думаю, что эта статья будет полезна, когда вы начните возиться с этими пакетами.

Весь исходный код из этой статьи доступен на GitHub.

Comments

No comments yet
Yurij Finiv

Yurij Finiv

Full stack

Про мене

Professional Fullstack Developer with extensive experience in website and desktop application development. Proficient in a wide range of tools and technologies, including Bootstrap, Tailwind, HTML5, CSS3, PUG, JavaScript, Alpine.js, jQuery, PHP, MODX, and Node.js. Skilled in website development using Symfony, MODX, and Laravel. Experience: Contributed to the development and translation of MODX3 i...

Об авторе CrazyBoy49z
WORK EXPERIENCE
Контакты
Ukraine, Lutsk
+380979856297