feat: 增强管理员权限管理,添加 RBAC 支持,更新 AdminUser 模型以处理角色和权限,更新登录接口返回权限信息,扩展数据库填充器以同步角色权限
This commit is contained in:
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::table('reconcile_jobs', function (Blueprint $table): void {
|
||||
$table->foreignId('admin_user_id')
|
||||
->nullable()
|
||||
->constrained('admin_users')
|
||||
->nullOnDelete();
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('reconcile_jobs', function (Blueprint $table): void {
|
||||
$table->dropConstrainedForeignId('admin_user_id');
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -2,53 +2,141 @@
|
||||
|
||||
namespace Database\Seeders;
|
||||
|
||||
use App\Models\AdminPermission;
|
||||
use App\Models\AdminRole;
|
||||
use App\Models\AdminUser;
|
||||
use Illuminate\Database\Seeder;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
/**
|
||||
* 后台角色(super_admin)、若干权限占位;本地演示:账号 **admin** / **123456**(仅限非 production)。
|
||||
* 后台 RBAC:与 {@see AdminUser::ROLE_SUPER_ADMIN} 及 PRD 对齐。
|
||||
*
|
||||
* - 角色 slug:`01-产品文档.md` §3 + `04-领域字典与编码规范.md` §11
|
||||
* - 权限点 slug:`01-产品文档.md` §8「功能」行 → `prd.{功能键}.{动作}`,路由中间件引用同表
|
||||
*
|
||||
* 演示账号 **admin** / **123456**(仅限非 production)。
|
||||
*/
|
||||
class AdminRbacAndUserSeeder extends Seeder
|
||||
{
|
||||
/** @return list<array{slug: string, name: string}> */
|
||||
private function permissionDefinitions(): array
|
||||
{
|
||||
return [
|
||||
['slug' => 'prd.users.manage', 'name' => '§8 用户管理·可管理'],
|
||||
['slug' => 'prd.users.view_finance', 'name' => '§8 用户管理·财务查看'],
|
||||
['slug' => 'prd.users.view_cs', 'name' => '§8 用户管理·客服单用户'],
|
||||
|
||||
['slug' => 'prd.play_switch.manage', 'name' => '§8 玩法开关·可管理'],
|
||||
['slug' => 'prd.odds.manage', 'name' => '§8 赔率配置·可管理'],
|
||||
['slug' => 'prd.risk_cap.manage', 'name' => '§8 封顶配置·可管理'],
|
||||
['slug' => 'prd.risk_cap.view', 'name' => '§8 封顶配置·查看'],
|
||||
['slug' => 'prd.rebate.manage', 'name' => '§8 佣金/回水·可管理'],
|
||||
['slug' => 'prd.rebate.view', 'name' => '§8 佣金/回水·查看'],
|
||||
['slug' => 'prd.jackpot.manage', 'name' => '§8 Jackpot 配置·可管理'],
|
||||
['slug' => 'prd.jackpot.view', 'name' => '§8 Jackpot 配置·查看'],
|
||||
|
||||
['slug' => 'prd.draw_result.manage', 'name' => '§8 开奖结果录入·可管理'],
|
||||
['slug' => 'prd.draw_result.view', 'name' => '§8 开奖结果·查看'],
|
||||
['slug' => 'prd.draw_reopen.manage', 'name' => '§8 开奖结果重开·可管理'],
|
||||
|
||||
['slug' => 'prd.payout.manage', 'name' => '§8 派彩确认·可管理'],
|
||||
['slug' => 'prd.payout.review', 'name' => '§8 派彩确认·可审核'],
|
||||
['slug' => 'prd.payout.view', 'name' => '§8 派彩确认·查看'],
|
||||
|
||||
['slug' => 'prd.wallet_reconcile.manage', 'name' => '§8 钱包对账·可管理'],
|
||||
['slug' => 'prd.wallet_reconcile.view', 'name' => '§8 钱包对账·查看'],
|
||||
['slug' => 'prd.wallet_reconcile.view_cs', 'name' => '§8 钱包对账·客服单用户'],
|
||||
|
||||
['slug' => 'prd.wallet_adjust.manage', 'name' => '§8 补单/冲正·可管理'],
|
||||
|
||||
['slug' => 'prd.report.all', 'name' => '§8 报表·全部'],
|
||||
['slug' => 'prd.report.risk', 'name' => '§8 报表·风控'],
|
||||
['slug' => 'prd.report.finance', 'name' => '§8 报表·财务'],
|
||||
['slug' => 'prd.report.player', 'name' => '§8 报表·单用户'],
|
||||
|
||||
['slug' => 'prd.audit.all', 'name' => '§8 审计日志·全部'],
|
||||
['slug' => 'prd.audit.self', 'name' => '§8 审计日志·自身相关'],
|
||||
['slug' => 'prd.audit.finance', 'name' => '§8 审计日志·资金相关'],
|
||||
|
||||
['slug' => 'prd.player_freeze.manage', 'name' => '§8 冻结/解冻玩家·可管理'],
|
||||
];
|
||||
}
|
||||
|
||||
/** @param list<string> $slugs */
|
||||
private function syncRolePermissions(AdminRole $role, array $slugs): void
|
||||
{
|
||||
$ids = AdminPermission::query()->whereIn('slug', $slugs)->pluck('id')->all();
|
||||
$role->permissions()->sync($ids);
|
||||
}
|
||||
|
||||
public function run(): void
|
||||
{
|
||||
$now = now();
|
||||
foreach ($this->permissionDefinitions() as $row) {
|
||||
AdminPermission::query()->updateOrCreate(
|
||||
['slug' => $row['slug']],
|
||||
['name' => $row['name']],
|
||||
);
|
||||
}
|
||||
|
||||
DB::table('admin_roles')->updateOrInsert(
|
||||
['slug' => 'super_admin'],
|
||||
[
|
||||
'name' => 'Super Admin',
|
||||
'created_at' => $now,
|
||||
'updated_at' => $now,
|
||||
],
|
||||
);
|
||||
/** @var int $rid */
|
||||
$rid = (int) DB::table('admin_roles')->where('slug', 'super_admin')->value('id');
|
||||
|
||||
$perms = [
|
||||
['slug' => 'admin.dashboard', 'name' => 'Dashboard'],
|
||||
['slug' => 'admin.players.read', 'name' => 'View players'],
|
||||
['slug' => 'admin.wallet.read', 'name' => 'View wallets'],
|
||||
$legacySlugs = [
|
||||
'admin.dashboard', 'admin.players.read', 'admin.wallet.read', 'admin.draws.read',
|
||||
'admin.draws.publish', 'admin.settlement.run', 'admin.settlement.read', 'admin.jackpot.read',
|
||||
'admin.jackpot.write', 'admin.config.read', 'admin.config.write', 'admin.audit.read',
|
||||
'admin.reports.manage', 'admin.reconcile.manage',
|
||||
];
|
||||
foreach ($perms as $p) {
|
||||
DB::table('admin_permissions')->updateOrInsert(
|
||||
['slug' => $p['slug']],
|
||||
[
|
||||
'name' => $p['name'],
|
||||
'created_at' => $now,
|
||||
'updated_at' => $now,
|
||||
],
|
||||
);
|
||||
}
|
||||
AdminPermission::query()->whereIn('slug', $legacySlugs)->delete();
|
||||
|
||||
$pidRows = DB::table('admin_permissions')->whereIn('slug', array_column($perms, 'slug'))->pluck('id');
|
||||
foreach ($pidRows as $pid) {
|
||||
DB::table('admin_role_permissions')->updateOrInsert(
|
||||
['role_id' => $rid, 'permission_id' => $pid],
|
||||
[],
|
||||
);
|
||||
}
|
||||
$super = AdminRole::query()->updateOrCreate(
|
||||
['slug' => AdminUser::ROLE_SUPER_ADMIN],
|
||||
['name' => '超级管理员'],
|
||||
);
|
||||
$this->syncRolePermissions($super, array_column($this->permissionDefinitions(), 'slug'));
|
||||
|
||||
$risk = AdminRole::query()->updateOrCreate(
|
||||
['slug' => 'risk_operator'],
|
||||
['name' => '风控运营员'],
|
||||
);
|
||||
$this->syncRolePermissions($risk, [
|
||||
'prd.play_switch.manage',
|
||||
'prd.odds.manage',
|
||||
'prd.risk_cap.manage',
|
||||
'prd.rebate.manage',
|
||||
'prd.jackpot.manage',
|
||||
'prd.draw_result.manage',
|
||||
'prd.payout.review',
|
||||
'prd.wallet_reconcile.view',
|
||||
'prd.report.risk',
|
||||
'prd.audit.self',
|
||||
'prd.player_freeze.manage',
|
||||
]);
|
||||
|
||||
$finance = AdminRole::query()->updateOrCreate(
|
||||
['slug' => 'finance'],
|
||||
['name' => '财务/对账员'],
|
||||
);
|
||||
$this->syncRolePermissions($finance, [
|
||||
'prd.users.view_finance',
|
||||
'prd.risk_cap.view',
|
||||
'prd.rebate.view',
|
||||
'prd.jackpot.view',
|
||||
'prd.draw_result.view',
|
||||
'prd.payout.view',
|
||||
'prd.wallet_reconcile.manage',
|
||||
'prd.wallet_adjust.manage',
|
||||
'prd.report.finance',
|
||||
'prd.audit.finance',
|
||||
]);
|
||||
|
||||
$cs = AdminRole::query()->updateOrCreate(
|
||||
['slug' => 'customer_service'],
|
||||
['name' => '客服人员'],
|
||||
);
|
||||
$this->syncRolePermissions($cs, [
|
||||
'prd.users.view_cs',
|
||||
'prd.draw_result.view',
|
||||
'prd.wallet_reconcile.view_cs',
|
||||
'prd.report.player',
|
||||
]);
|
||||
|
||||
$username = 'admin';
|
||||
AdminUser::query()->updateOrCreate(
|
||||
@@ -56,17 +144,17 @@ class AdminRbacAndUserSeeder extends Seeder
|
||||
[
|
||||
'name' => '超级管理员',
|
||||
'email' => null,
|
||||
/** 明文;模型 casts `password => hashed`,勿在生产库使用种子弱口令 */
|
||||
'password' => '123456',
|
||||
'status' => 0,
|
||||
],
|
||||
);
|
||||
|
||||
/** @var int $uid */
|
||||
$uid = (int) AdminUser::query()->where('username', $username)->value('id');
|
||||
DB::table('admin_user_roles')->updateOrInsert(
|
||||
['admin_user_id' => $uid, 'role_id' => $rid],
|
||||
[],
|
||||
);
|
||||
/** @var AdminUser $admin */
|
||||
$admin = AdminUser::query()->where('username', $username)->firstOrFail();
|
||||
$admin->roles()->sync([(int) $super->getKey()]);
|
||||
|
||||
DB::table('admin_user_roles')->where('admin_user_id', $admin->id)
|
||||
->whereNotIn('role_id', [(int) $super->getKey()])
|
||||
->delete();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user