Рассмотрим пример настройки конфигурации Moonshine с сторонней авторизацией на примере пакета Spatie-Permission в самой базовой версии
Используемая версия Moonshine не ниже v1.60.1
1) Устанавливаем пакет spatie-permision через composer
composer require spatie/laravel-permission
2) Необязательно: service provider автоматически зарегистрируется. Или вы можете вручную добавить поставщика услуг в свой файл config/app.php:
'providers' => [
// ...
Spatie\Permission\PermissionServiceProvider::class,
];
3) Опубликуйте миграцию и файл конфигурации config/permission.php с помощью:
php artisan vendor:publish --provider="Spatie\Permission\PermissionServiceProvider"
4) Очистите кеш конфигурации с помощью любой из этих команд:
php artisan optimize:clear
# или
php artisan config:clear
5)Запустите миграцию: после публикации и настройки конфигурации и миграции вы можете создать таблицы для этого пакета, выполнив:
php artisan migrate
5.1) Добавьте trait HasRoles в вашу модель пользователя и HasMoonShineChangeLog(Документация) для просмотра лога изменений
class User extends Authenticatable
{
use HasFactory, Notifiable;
use HasRoles ;
use HasMoonShineChangeLog;
6)Создайте свою миграцию для добавления доп. полей в существующие модели Spatie.
Так как в стандартной миграции Spatie нет описания полей, ролей и прав ,поле description ,а также нет дефолтного значения поля guard_name советую создать дополнитнльную миграцию для добавления и изменения этих полей.
Поле description даст некоторое удобство при создании ролей и прав - вы сможете добавлять свое описание .
php artisan make:migration alter_column_in_spaties_table
примерно такого содержания:
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
$tableNames = config('permission.table_names');
$columnNames = config('permission.column_names');
$teams = config('permission.teams');
if (empty($tableNames)) {
throw new \Exception('Error: config/permission.php not loaded. Run [php artisan config:clear] and try again.');
}
if ($teams && empty($columnNames['team_foreign_key'] ?? null)) {
throw new \Exception('Error: team_foreign_key on config/permission.php not loaded. Run [php artisan config:clear] and try again.');
}
Schema::table($tableNames['roles'], function (Blueprint $table) use ($teams, $columnNames) {
$table->string('description')->nullable(); // For MySQL 8.0 use string('name', 125);
$table->string('guard_name')->default('web')->change(); // For MySQL 8.0 use string('guard_name', 125);
});
Schema::table($tableNames['permissions'], function (Blueprint $table) use ($teams, $columnNames) {
$table->string('description')->nullable(); // For MySQL 8.0 use string('name', 125);
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
$tableNames = config('permission.table_names');
if (empty($tableNames)) {
throw new \Exception('Error: config/permission.php not found and defaults could not be merged. Please publish the package configuration before proceeding, or drop the tables manually.');
}
Schema::dropColumns($tableNames['roles'],'description');
Schema::dropColumns($tableNames['permissions'],'description');
}
};
Запустите миграцию если нужно внести дополнительные изменения выполнив:
php artisan migrate
7) Внесите изменения в файл config/moonshine.php - места где внесены изменения помечены (//<-Изменили)
<?php
use MoonShine\Exceptions\MoonShineNotFoundException;
use MoonShine\Models\MoonshineUser;
return [
'dir' => 'app/MoonShine',
'namespace' => 'App\MoonShine',
'title' => env('MOONSHINE_TITLE', 'MoonShine'),
'logo' => env('MOONSHINE_LOGO', ''),
'route' => [
'prefix' => env('MOONSHINE_ROUTE_PREFIX', 'admin'), //<-Изменили
'middleware' => ['moonshine'],
'custom_page_slug' => 'custom_page',
'notFoundHandler' => MoonShineNotFoundException::class
],
'use_migrations' => true,
'use_notifications' => true,
'auth' => [
'enable' => true,
'fields' => [
'username' => 'email',
'password' => 'password',
'name' => 'name',
'avatar' => 'avatar'
],
'guard' => 'web', //'moonshine', //<-Изменили
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
], //<-Изменили
'moonshine' => [
'driver' => 'session',
'provider' => 'moonshine',
],
],
'providers' => [
'users' => [
'driver' => 'eloquent',
'model' => App\Models\User::class, //<-Изменили
],
'moonshine' => [
'driver' => 'eloquent',
'model' => App\Models\User::class, //<-Изменили MoonshineUser::class,
],
],
'footer' => ''
],
'locales' => [
'ru'
],
'middlewares' => [],
'tinymce' => [
'file_manager' => false, // or 'laravel-filemanager' prefix for lfm
'token' => env('MOONSHINE_TINYMCE_TOKEN', ''),
'version' => env('MOONSHINE_TINYMCE_VERSION', '6')
],
'socialite' => [
// 'driver' => 'path_to_image_for_button'
],
'header' => null, // blade path
'footer' => [
'copyright' => 'Made with ❤️ by CutCode',
'nav' => [
'https://github.com/moonshine-software/moonshine/blob/1.5.x/LICENSE.md' => 'License',
'https://moonshine.cutcode.dev' => 'Documentation',
'https://github.com/moonshine-software/moonshine' => 'GitHub',
],
]
];
Если вы не хотите использовать аватар, то укажите в конфиге 'avatar'=>''
или 'avatar'=>false
в ином случае создайте миграцию php artisan make:migration add_avatar_in_users_table
php artisan make:migration add_avatar_in_users_table
и заполните ее
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('users', function (Blueprint $table) {
$table->string('avatar')->nullable();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropColumns('users','avatar');
}
};
Это необходимо для использования avatar в персональном профиле , но вы можете переопредилить название этого поля в config/moonshine.php (Документация) .
8) Создайте ( php artisan moonshine:resource PermissionResource ) (Документация) , 2 ресурса которые есть по умолчанию можно отредактировать или создать свои . В данном случае мы отредактируем UserResourse, UserRolesResourse
Примеры: App\MoonShine\Resources\UserResourse:
<?php
namespace App\MoonShine\Resources;
use App\MoonShine\Resources\UserRolesResourse;
use Illuminate\Database\Eloquent\Model;
use App\Models\User;
use Illuminate\Support\Facades\Http;
use Illuminate\Validation\Rule;
use MoonShine\Actions\ExportAction;
use MoonShine\Decorations\Block;
use MoonShine\Decorations\Column;
use MoonShine\Decorations\Grid;
use MoonShine\Fields\BelongsTo;
use MoonShine\Fields\BelongsToMany;
use App\MoonShine\Fields\BelongToManyField;
use MoonShine\Fields\Date;
use MoonShine\Fields\Email;
use MoonShine\Fields\HasMany;
use MoonShine\Fields\Image;
use MoonShine\Fields\Password;
use MoonShine\Fields\PasswordRepeat;
use MoonShine\Fields\Text;
use MoonShine\Filters\DateFilter;
use MoonShine\Filters\TextFilter;
use MoonShine\FormComponents\ChangeLogFormComponent;
use MoonShine\FormComponents\PermissionFormComponent;
use MoonShine\Models\MoonshineUser;
use MoonShine\Models\MoonshineUserRole;
use MoonShine\Resources\MoonShineUserRoleResource;
use MoonShine\Resources\Resource;
use MoonShine\Fields\ID;
use MoonShine\Actions\FiltersAction;
use MoonShine\Traits\Resource\WithUserPermissions;
class UserResource extends Resource
{
//use WithUserPermissions;//<-Изменили
public static string $model = User::class; //<-Изменили
public string $titleField = 'name';
protected static bool $system = true;
public function title(): string
{
return trans('moonshine::ui.resource.admins_title');
}
public function fields(): array
{
return [
Grid::make([
Column::make([
Block::make(trans('moonshine::ui.resource.main_information'), [
ID::make()
->sortable()
->useOnImport()
->showOnExport(),
Text::make(trans('moonshine::ui.resource.name'), 'name')
->required()
->useOnImport()
->showOnExport(),
Image::make(trans('moonshine::ui.resource.avatar'), 'avatar')
->removable()
->showOnExport()
->disk(config('filesystems.default'))
->dir('moonshine_users')
->allowedExtensions(['jpg', 'png', 'jpeg', 'gif']),
Date::make(trans('moonshine::ui.resource.created_at'), 'created_at')
->format("d.m.Y")
->default(now()->toDateTimeString())
->sortable()
->hideOnForm()
->showOnExport(),
Email::make(trans('moonshine::ui.resource.email'), 'email')
->sortable()
->showOnExport()
->required(),
BelongsToMany::make(
trans('moonshine::ui.resource.role'),
'roles',
'name'//,
//new UserRolesResourse()
)
->showOnExport()->select()->inLine('',true),
//Тест
BelongsToMany::make(
trans('moonshine::ui.resource.role'),
'roles',
// 'name'//,
new UserRolesResourse()
)
->showOnExport()->inLine('',true)->hideOnIndex(),
]),
Block::make(trans('moonshine::ui.resource.change_password'), [
Password::make(trans('moonshine::ui.resource.password'), 'password')
->customAttributes(['autocomplete' => 'new-password'])
->hideOnIndex()
->hideOnExport()
->hideOnDetail()
->eye(),
PasswordRepeat::make(trans('moonshine::ui.resource.repeat_password'), 'password_repeat')
->customAttributes(['autocomplete' => 'confirm-password'])
->hideOnIndex()
->hideOnExport()
->hideOnDetail()
->eye(),
]),
]),
]),
];
}
public function components(): array
{
return [
// ChangeLogFormComponent::make('Change log')
// ->canSee(fn ($user) => $user->moonshine_user_role_id === 1),
ChangeLogFormComponent::make('Change log')
->canSee(fn ($user) => $user->hasRole('admin')),
// ->canSee(fn ($user) => $user->moonshine_user_role_id === 1),
];
}
public function rules($item): array
{
return [
'name' => 'required',
// 'moonshine_user_role_id' => 'required',
'email' => [
'sometimes',
'bail',
'required',
'email',
// Rule::unique('moonshine_users')->ignoreModel($item),
Rule::unique('users')->ignoreModel($item),
],
'password' => ! $item->exists
? 'required|min:6|required_with:password_repeat|same:password_repeat'
: 'sometimes|nullable|min:6|required_with:password_repeat|same:password_repeat',
];
}
public function search(): array
{
return ['id', 'name'];
}
public function filters(): array
{
return [
TextFilter::make(trans('moonshine::ui.resource.name'), 'name'),
DateFilter::make(trans('moonshine::ui.resource.created_at'), 'created_at'),
];
}
public function actions(): array
{
return [
ExportAction::make(trans('moonshine::ui.export')),
];
}
}
App\MoonShine\Resources\UserRolesResourse
<?php
namespace App\MoonShine\Resources;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Validation\Rule;
use MoonShine\Decorations\Block;
use MoonShine\Fields\BelongsTo;
use MoonShine\Fields\Text;
use MoonShine\Filters\TextFilter;
use Spatie\Permission\Models\Role as Role;
use MoonShine\Fields\BelongsToMany;
use App\MoonShine\Fields\BelongToManyField;
use Spatie\Permission\Models\Permission as Permission;
use MoonShine\Resources\Resource;
use MoonShine\Fields\ID;
use MoonShine\Actions\FiltersAction;
class UserRolesResourse extends Resource
{
public static string $model = \Spatie\Permission\Models\Role::class; //<-Изменили
public string $titleField = 'name';
protected static bool $system = false;
protected bool $createInModal = true;
protected bool $editInModal = true;
public function title(): string
{
return trans('moonshine::ui.resource.role');
}
public function fields(): array
{
return [
Block::make(trans('moonshine::ui.resource.main_information'), [
ID::make()
->sortable()
->showOnExport(),
Text::make(trans('moonshine::ui.resource.role_name'), 'name')
->required()
->showOnExport(),
BelongsToMany::make('Права доступа', 'permissions', new UserResource(),
)->select()->inLine('',true)
]),
];
}
public function rules($item): array
{
return [
'name' => [
'required',
'min:5',
Rule::unique('roles')->ignoreModel($item), //<-Изменили
],
];
}
public function search(): array
{
return ['id', 'name'];
}
public function filters(): array
{
return [
TextFilter::make(trans('moonshine::ui.resource.role_name'), 'name'),
];
}
public function actions(): array
{
return [];
}
}
App\MoonShine\Resources\PermissionResourse:
<?php
namespace App\MoonShine\Resources;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Validation\Rule;
use MoonShine\Fields\Text;
use Spatie\Permission\Models\Permission;
use MoonShine\Resources\Resource;
use MoonShine\Fields\ID;
use MoonShine\Actions\FiltersAction;
class PermissionResource extends Resource
{
public static string $model = Permission::class;
public static string $title = 'Права доступа';
public function fields(): array
{
return [
ID::make()->sortable(),
Text::make(trans('moonshine::ui.resource.name'), 'name')
->required()
->useOnImport()
->showOnExport(),
];
}
public function rules(Model $item): array
{
return [
'name' => [
'required',
'min:5',
Rule::unique('permissions')->ignoreModel($item), //<-Изменили
],
];
}
public function search(): array
{
return ['id'];
}
public function filters(): array
{
return [];
}
public function actions(): array
{
return [
FiltersAction::make(trans('moonshine::ui.filters')),
];
}
}
9) Добавьте пункты в Меню в классе MoonShineServiceProvider (Документация):
MenuGroup::make('moonshine::ui.resource.system', [
MenuItem::make('Пользователи', new UserResource())
->translatable()
->icon('users'),
MenuItem::make('Роли', new UserRolesResourse())
->translatable()
->icon('bookmark'),
MenuItem::make('Права', new PermissionResource())
->translatable()
->icon('bookmark'),
])->translatable(),
10) По всем возможнястям авторизации Spatie можете ознакомиться на оф. сайте spatie/laravel-permission