
本文介绍如何使用 laravel + spatie laravel permission 构建清晰、可维护的角色-权限分配表格界面,支持按模块(如用户、订单、文章)分组设置 view/create/edit/delete 权限,并实现后端校验与自动权限创建。
本文介绍如何使用 laravel + spatie laravel permission 构建清晰、可维护的角色-权限分配表格界面,支持按模块(如用户、订单、文章)分组设置 view/create/edit/delete 权限,并实现后端校验与自动权限创建。
在权限管理系统中,常见的需求是为不同角色(如管理员、编辑、审核员)分配细粒度的模块级操作权限(如“用户模块 → 查看/创建/编辑/删除”)。原始代码将权限按行遍历、角色横向重复渲染,导致结构混乱且无法对齐模块维度;而理想结构应以模块为行、操作类型为列、角色权限状态为复选框,形成直观的二维矩阵。
✅ 正确的前端结构设计
核心思路是:固定模块列表,动态渲染每模块下的四类权限复选框,而非按权限对象循环。以下是一个标准 Blade 模板示例(兼容 Bootstrap 5 + Spatie):
<form action="{{ route('settings.roles.store') }}" method="POST">
@csrf
<div class="mb-4">
<label for="role_name" class="form-label fw-bold">角色名称</label>
<input type="text" id="role_name" name="role_name" class="form-control" required
placeholder="例如:内容编辑员" value="{{ old('role_name') }}">
</div>
<div class="mb-4">
<label class="form-label fw-bold mb-3">模块权限配置</label>
<div class="table-responsive">
<table class="table table-bordered align-middle">
<thead class="table-light">
<tr>
<th scope="col" width="200">模块</th>
<th scope="col" class="text-center">查看</th>
<th scope="col" class="text-center">创建</th>
<th scope="col" class="text-center">编辑</th>
<th scope="col" class="text-center">删除</th>
</tr>
</thead>
<tbody>
<!-- 用户模块 -->
<tr>
<td class="fw-medium">用户管理</td>
<td class="text-center">
<div class="form-check form-switch d-inline-block me-0">
<input class="form-check-input" type="checkbox" name="permissions[]"
value="users.view" {{ in_array('users.view', $existingPermissions ?? []) ? 'checked' : '' }}>
</div>
</td>
<td class="text-center">
<div class="form-check form-switch d-inline-block me-0">
<input class="form-check-input" type="checkbox" name="permissions[]"
value="users.create" {{ in_array('users.create', $existingPermissions ?? []) ? 'checked' : '' }}>
</div>
</td>
<td class="text-center">
<div class="form-check form-switch d-inline-block me-0">
<input class="form-check-input" type="checkbox" name="permissions[]"
value="users.update" {{ in_array('users.update', $existingPermissions ?? []) ? 'checked' : '' }}>
</div>
</td>
<td class="text-center">
<div class="form-check form-switch d-inline-block me-0">
<input class="form-check-input" type="checkbox" name="permissions[]"
value="users.delete" {{ in_array('users.delete', $existingPermissions ?? []) ? 'checked' : '' }}>
</div>
</td>
</tr>
<!-- 订单模块 -->
<tr>
<td class="fw-medium">订单管理</td>
<td class="text-center">
<input class="form-check-input" type="checkbox" name="permissions[]"
value="orders.view" {{ in_array('orders.view', $existingPermissions ?? []) ? 'checked' : '' }}>
</td>
<td class="text-center">
<input class="form-check-input" type="checkbox" name="permissions[]"
value="orders.create" {{ in_array('orders.create', $existingPermissions ?? []) ? 'checked' : '' }}>
</td>
<td class="text-center">
<input class="form-check-input" type="checkbox" name="permissions[]"
value="orders.update" {{ in_array('orders.update', $existingPermissions ?? []) ? 'checked' : '' }}>
</td>
<td class="text-center">
<input class="form-check-input" type="checkbox" name="permissions[]"
value="orders.delete" {{ in_array('orders.delete', $existingPermissions ?? []) ? 'checked' : '' }}>
</td>
</tr>
<!-- 其他模块依此类推... -->
</tbody>
</table>
</div>
</div>
<button type="submit" class="btn btn-primary px-6">保存角色与权限</button>
</form>? 关键要点:
- name="permissions[]" 统一收集所有勾选的权限字符串(如 "users.view"),便于后端批量同步;
- 使用 in_array() 判断当前角色是否已拥有某权限,实现表单回显;
- 模块名硬编码或从配置/数据库读取,确保前后端权限命名一致(推荐 module.action 格式)。
⚙️ 后端权限同步逻辑(Controller)
在控制器中,需确保权限存在后再绑定至角色。推荐封装为服务类,但最小可行实现如下:
use Spatie\Permission\Models\Role;
use Spatie\Permission\Models\Permission;
use Illuminate\Support\Facades\DB;
public function store(Request $request)
{
$request->validate([
'role_name' => 'required|string|max:191|unique:roles,name',
'permissions' => 'array',
'permissions.*' => 'string|exists:permissions,name'
]);
$permissions = $request->input('permissions', []);
DB::beginTransaction();
try {
// 创建角色
$role = Role::create(['name' => $request->role_name]);
// 自动创建缺失权限(避免手动 seed)
foreach ($permissions as $permissionName) {
Permission::firstOrCreate(
['name' => $permissionName],
['guard_name' => 'web']
);
}
// 同步权限(覆盖式,确保精准)
$role->syncPermissions($permissions);
DB::commit();
return redirect()->route('settings.roles.index')->with('success', '角色创建成功!');
} catch (\Exception $e) {
DB::rollBack();
throw $e;
}
}? 权限校验与最佳实践
- 在中间件或控制器中使用 auth()->user()->can('users.edit') 进行授权判断;
- 前端按钮/链接应配合 @can('users.delete') Blade 指令做条件渲染,避免越权入口;
- 权限命名建议统一规范:{resource}.{action}(如 posts.restore, settings.update),便于扩展和语义理解;
- 生产环境务必禁用未定义权限的自动创建(开发期可用,上线前移除或加开关)。
通过该结构,你将获得一张真正符合 RBAC(基于角色的访问控制)模型的权限配置表——模块清晰、操作明确、数据可靠,且易于后续扩展自定义权限或动态模块加载。

















