本文目录导读:

我来详细介绍ThinkPHP项目中角色与权限分配的实现方案,包括数据库设计、核心代码实现和完整示例。
数据库设计
数据表结构
-- 用户表 CREATE TABLE `user` ( `id` int(11) NOT NULL AUTO_INCREMENT, `username` varchar(50) NOT NULL COMMENT '用户名', `password` varchar(255) NOT NULL COMMENT '密码', `email` varchar(100) DEFAULT NULL, `status` tinyint(1) DEFAULT '1' COMMENT '状态:1启用,0禁用', `create_time` datetime DEFAULT NULL, `update_time` datetime DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; -- 角色表 CREATE TABLE `role` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(50) NOT NULL COMMENT '角色名称', `description` varchar(255) DEFAULT NULL COMMENT '角色描述', `status` tinyint(1) DEFAULT '1' COMMENT '状态', `create_time` datetime DEFAULT NULL, `update_time` datetime DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; -- 权限表 CREATE TABLE `permission` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(50) NOT NULL COMMENT '权限名称', `code` varchar(100) NOT NULL COMMENT '权限代码', `type` tinyint(1) DEFAULT '1' COMMENT '类型:1菜单,2按钮', `parent_id` int(11) DEFAULT '0' COMMENT '父级ID', `route` varchar(255) DEFAULT NULL COMMENT '路由地址', `sort` int(11) DEFAULT '0' COMMENT '排序', `status` tinyint(1) DEFAULT '1', PRIMARY KEY (`id`), UNIQUE KEY `uk_code` (`code`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; -- 用户-角色关联表 CREATE TABLE `user_role` ( `user_id` int(11) NOT NULL, `role_id` int(11) NOT NULL, PRIMARY KEY (`user_id`,`role_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; -- 角色-权限关联表 CREATE TABLE `role_permission` ( `role_id` int(11) NOT NULL, `permission_id` int(11) NOT NULL, PRIMARY KEY (`role_id`,`permission_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
核心模型类
User模型
<?php
namespace app\common\model;
use think\Model;
use think\model\concern\SoftDelete;
class User extends Model
{
use SoftDelete;
protected $deleteTime = 'delete_time';
// 关联角色
public function roles()
{
return $this->belongsToMany(Role::class, 'user_role', 'role_id', 'user_id');
}
// 获取用户所有权限
public function getPermissions()
{
$roles = $this->roles()->where('status', 1)->select();
$permissionIds = [];
foreach ($roles as $role) {
$permissionIds = array_merge(
$permissionIds,
$role->permissions()->column('id')
);
}
return array_unique($permissionIds);
}
// 检查是否有指定权限
public function hasPermission($permissionCode)
{
$permissionIds = $this->getPermissions();
if (empty($permissionIds)) {
return false;
}
return Permission::whereIn('id', $permissionIds)
->where('code', $permissionCode)
->count() > 0;
}
// 检查是否有指定角色
public function hasRole($roleName)
{
return $this->roles()
->where('name', $roleName)
->where('status', 1)
->count() > 0;
}
}
Role模型
<?php
namespace app\common\model;
use think\Model;
class Role extends Model
{
// 关联权限
public function permissions()
{
return $this->belongsToMany(Permission::class, 'role_permission', 'permission_id', 'role_id');
}
// 关联用户
public function users()
{
return $this->belongsToMany(User::class, 'user_role', 'user_id', 'role_id');
}
// 给角色分配权限
public function assignPermissions(array $permissionIds)
{
return $this->permissions()->detach()
->then(function () use ($permissionIds) {
return $this->permissions()->attach($permissionIds);
});
}
}
Permission模型
<?php
namespace app\common\model;
use think\Model;
class Permission extends Model
{
// 获取权限树形结构
public static function getTree()
{
$permissions = self::order('sort', 'asc')->select()->toArray();
return self::buildTree($permissions);
}
// 构建树形结构
private static function buildTree(array $items, $parentId = 0)
{
$tree = [];
foreach ($items as $item) {
if ($item['parent_id'] == $parentId) {
$children = self::buildTree($items, $item['id']);
if ($children) {
$item['children'] = $children;
}
$tree[] = $item;
}
}
return $tree;
}
}
鉴权中间件
权限检查中间件
<?php
namespace app\middleware;
use think\Request;
use think\Response;
use app\common\model\User;
class CheckPermission
{
public function handle(Request $request, \Closure $next, $permission = null)
{
// 获取当前登录用户
$userId = session('user_id');
if (!$userId) {
return redirect('/login');
}
$user = User::find($userId);
if (!$user || $user->status != 1) {
return redirect('/login');
}
// 超级管理员直接通过
if ($user->hasRole('admin')) {
return $next($request);
}
// 检查权限
if ($permission && !$user->hasPermission($permission)) {
if ($request->isAjax()) {
return json(['code' => 403, 'msg' => '没有权限操作']);
}
abort(403, '没有权限访问');
}
// 将用户对象绑定到请求
$request->user = $user;
return $next($request);
}
}
权限管理控制器
用户管理控制器
<?php
namespace app\admin\controller;
use think\Request;
use app\common\model\User;
use app\common\model\Role;
use app\common\model\UserRole;
class UserController extends BaseController
{
// 用户列表
public function index(Request $request)
{
$page = $request->param('page', 1);
$limit = $request->param('limit', 10);
$keyword = $request->param('keyword', '');
$query = User::with(['roles']);
if ($keyword) {
$query->where('username', 'like', "%{$keyword}%");
}
$list = $query->paginate([
'page' => $page,
'list_rows' => $limit
]);
return json([
'code' => 0,
'msg' => 'success',
'data' => $list->items(),
'count' => $list->total()
]);
}
// 创建用户
public function create(Request $request)
{
$data = $request->post();
$validate = new \app\admin\validate\UserValidate();
if (!$validate->scene('create')->check($data)) {
return json(['code' => 0, 'msg' => $validate->getError()]);
}
$user = new User();
$user->username = $data['username'];
$user->password = password_hash($data['password'], PASSWORD_DEFAULT);
$user->email = $data['email'] ?? '';
$user->status = $data['status'] ?? 1;
$user->save();
// 分配角色
if (isset($data['role_ids']) && is_array($data['role_ids'])) {
$user->roles()->attach($data['role_ids']);
}
return json(['code' => 1, 'msg' => '创建成功']);
}
// 更新用户
public function update(Request $request, $id)
{
$user = User::find($id);
if (!$user) {
return json(['code' => 0, 'msg' => '用户不存在']);
}
$data = $request->post();
if (isset($data['password']) && $data['password']) {
$user->password = password_hash($data['password'], PASSWORD_DEFAULT);
}
if (isset($data['email'])) {
$user->email = $data['email'];
}
if (isset($data['status'])) {
$user->status = $data['status'];
}
$user->save();
// 更新角色
if (isset($data['role_ids']) && is_array($data['role_ids'])) {
$user->roles()->detach();
$user->roles()->attach($data['role_ids']);
}
return json(['code' => 1, 'msg' => '更新成功']);
}
// 删除用户(软删除)
public function delete($id)
{
$user = User::find($id);
if (!$user) {
return json(['code' => 0, 'msg' => '用户不存在']);
}
$user->delete();
return json(['code' => 1, 'msg' => '删除成功']);
}
// 分配角色
public function assignRole(Request $request)
{
$userId = $request->post('user_id');
$roleIds = $request->post('role_ids', []);
$user = User::find($userId);
if (!$user) {
return json(['code' => 0, 'msg' => '用户不存在']);
}
$user->roles()->detach();
$user->roles()->attach($roleIds);
return json(['code' => 1, 'msg' => '角色分配成功']);
}
}
角色管理控制器
<?php
namespace app\admin\controller;
use think\Request;
use app\common\model\Role;
use app\common\model\Permission;
class RoleController extends BaseController
{
// 角色列表
public function index()
{
$roles = Role::with(['permissions'])->select();
return json(['code' => 0, 'data' => $roles]);
}
// 创建角色
public function create(Request $request)
{
$data = $request->post();
$role = new Role();
$role->name = $data['name'];
$role->description = $data['description'] ?? '';
$role->save();
// 分配权限
if (isset($data['permission_ids']) && is_array($data['permission_ids'])) {
$role->permissions()->attach($data['permission_ids']);
}
return json(['code' => 1, 'msg' => '角色创建成功']);
}
// 更新角色
public function update(Request $request, $id)
{
$role = Role::find($id);
if (!$role) {
return json(['code' => 0, 'msg' => '角色不存在']);
}
$data = $request->post();
if (isset($data['name'])) {
$role->name = $data['name'];
}
if (isset($data['description'])) {
$role->description = $data['description'];
}
$role->save();
// 更新权限
if (isset($data['permission_ids'])) {
$role->permissions()->detach();
$role->permissions()->attach($data['permission_ids']);
}
return json(['code' => 1, 'msg' => '角色更新成功']);
}
// 删除角色
public function delete($id)
{
$role = Role::find($id);
if (!$role) {
return json(['code' => 0, 'msg' => '角色不存在']);
}
// 检查是否有用户使用该角色
if ($role->users()->count() > 0) {
return json(['code' => 0, 'msg' => '该角色已被使用,无法删除']);
}
$role->delete();
$role->permissions()->detach();
return json(['code' => 1, 'msg' => '角色删除成功']);
}
// 分配权限
public function assignPermission(Request $request)
{
$roleId = $request->post('role_id');
$permissionIds = $request->post('permission_ids', []);
$role = Role::find($roleId);
if (!$role) {
return json(['code' => 0, 'msg' => '角色不存在']);
}
$role->permissions()->detach();
$role->permissions()->attach($permissionIds);
return json(['code' => 1, 'msg' => '权限分配成功']);
}
}
权限管理控制器
<?php
namespace app\admin\controller;
use think\Request;
use app\common\model\Permission;
use think\facade\Cache;
class PermissionController extends BaseController
{
// 权限列表(树形)
public function index()
{
$tree = Permission::getTree();
return json(['code' => 0, 'data' => $tree]);
}
// 创建权限
public function create(Request $request)
{
$data = $request->post();
$permission = new Permission();
$permission->name = $data['name'];
$permission->code = $data['code'];
$permission->type = $data['type'] ?? 1;
$permission->parent_id = $data['parent_id'] ?? 0;
$permission->route = $data['route'] ?? '';
$permission->sort = $data['sort'] ?? 0;
$permission->save();
$this->clearCache();
return json(['code' => 1, 'msg' => '权限创建成功']);
}
// 更新权限
public function update(Request $request, $id)
{
$permission = Permission::find($id);
if (!$permission) {
return json(['code' => 0, 'msg' => '权限不存在']);
}
$data = $request->post();
if (isset($data['name'])) {
$permission->name = $data['name'];
}
if (isset($data['code'])) {
$permission->code = $data['code'];
}
if (isset($data['route'])) {
$permission->route = $data['route'];
}
$permission->save();
$this->clearCache();
return json(['code' => 1, 'msg' => '权限更新成功']);
}
// 删除权限
public function delete($id)
{
$permission = Permission::find($id);
if (!$permission) {
return json(['code' => 0, 'msg' => '权限不存在']);
}
// 检查是否有子权限
$hasChildren = Permission::where('parent_id', $id)->count();
if ($hasChildren > 0) {
return json(['code' => 0, 'msg' => '存在子权限,无法删除']);
}
$permission->delete();
$this->clearCache();
return json(['code' => 1, 'msg' => '权限删除成功']);
}
// 清除缓存
private function clearCache()
{
Cache::delete('all_permissions');
}
}
路由配置
<?php
// route/app.php
use think\facade\Route;
// 用户管理
Route::group('admin/user', function () {
Route::get('index', 'admin.User/index');
Route::post('create', 'admin.User/create');
Route::put('update/:id', 'admin.User/update');
Route::delete('delete/:id', 'admin.User/delete');
Route::post('assign_role', 'admin.User/assignRole');
})->middleware([\app\middleware\CheckPermission::class]);
// 角色管理
Route::group('admin/role', function () {
Route::get('index', 'admin.Role/index');
Route::post('create', 'admin.Role/create');
Route::put('update/:id', 'admin.Role/update');
Route::delete('delete/:id', 'admin.Role/delete');
Route::post('assign_permission', 'admin.Role/assignPermission');
})->middleware([\app\middleware\CheckPermission::class]);
// 权限管理
Route::group('admin/permission', function () {
Route::get('index', 'admin.Permission/index');
Route::post('create', 'admin.Permission/create');
Route::put('update/:id', 'admin.Permission/update');
Route::delete('delete/:id', 'admin.Permission/delete');
})->middleware([\app\middleware\CheckPermission::class]);
模板示例
角色分配界面
<!-- role_assign.html -->
<div class="role-assign-form">
<form id="roleForm">
<div class="form-group">
<label>用户名</label>
<input type="text" name="username" value="{$user.username}" readonly>
</div>
<div class="form-group">
<label>分配角色</label>
<div class="checkbox-group">
{volist name="roles" id="role"}
<label class="checkbox-inline">
<input type="checkbox" name="role_ids[]"
value="{$role.id}"
{if in_array($role.id, $userRoleIds)}checked{/if}>
{$role.name}
</label>
{/volist}
</div>
</div>
<div class="form-group">
<button type="submit" class="btn btn-primary">保存</button>
</div>
</form>
</div>
<script>
$(function() {
$('#roleForm').on('submit', function(e) {
e.preventDefault();
var roleIds = [];
$('input[name="role_ids[]"]:checked').each(function() {
roleIds.push($(this).val());
});
$.ajax({
url: '/admin/user/assign_role',
type: 'POST',
data: {
user_id: {$user.id},
role_ids: roleIds
},
success: function(res) {
if (res.code === 1) {
layer.msg('分配成功');
location.reload();
} else {
layer.msg(res.msg);
}
}
});
});
});
</script>
权限树形选择
<!-- permission_tree.html -->
<div class="permission-tree">
<ul id="permissionTree" class="ztree"></ul>
</div>
<script>
var setting = {
check: {
enable: true,
chkboxType: {"Y": "ps", "N": "ps"}
},
data: {
simpleData: {
enable: true,
idKey: "id",
pIdKey: "parent_id",
rootPId: 0
}
}
};
function initPermissionTree() {
$.ajax({
url: '/admin/permission/index',
type: 'GET',
success: function(res) {
if (res.code === 0) {
var tree = [];
var permissions = res.data;
function flattenTree(data, parentId) {
$.each(data, function(index, item) {
tree.push({
id: item.id,
parent_id: parentId || 0,
name: item.name,
open: parentId === 0
});
if (item.children && item.children.length > 0) {
flattenTree(item.children, item.id);
}
});
}
flattenTree(permissions, 0);
$.fn.zTree.init($("#permissionTree"), setting, tree);
}
}
});
}
// 获取选中的权限ID
function getSelectedPermissionIds() {
var treeObj = $.fn.zTree.getZTreeObj("permissionTree");
var nodes = treeObj.getCheckedNodes(true);
return nodes.map(function(node) {
return node.id;
});
}
</script>
权限校验辅助类
<?php
namespace app\common\auth;
use app\common\model\User;
use think\facade\Cache;
use think\facade\Session;
class AuthHelper
{
// 获取用户权限标识符
public static function getUserPermissionCodes()
{
$userId = Session::get('user_id');
$cacheKey = 'user_permissions_' . $userId;
// 尝试从缓存获取
$permissions = Cache::get($cacheKey);
if ($permissions) {
return $permissions;
}
// 查询数据库
$user = User::find($userId);
if (!$user) {
return [];
}
$roleIds = $user->roles()->column('id');
$permissions = [];
if (!empty($roleIds)) {
$permissionCodes = \app\common\model\RolePermission::alias('rp')
->join('permission p', 'p.id = rp.permission_id')
->whereIn('rp.role_id', $roleIds)
->column('p.code');
$permissions = array_unique($permissionCodes);
}
// 缓存30分钟
Cache::set($cacheKey, $permissions, 1800);
return $permissions;
}
// 清除用户权限缓存
public static function clearUserPermission($userId = null)
{
if ($userId) {
Cache::delete('user_permissions_' . $userId);
} else {
Cache::delete('user_permissions_' . Session::get('user_id'));
}
}
// 生成权限菜单树
public static function getMenuTree()
{
$permissionCodes = self::getUserPermissionCodes();
$query = \app\common\model\Permission::where('type', 1)
->where('status', 1)
->order('sort', 'asc');
$permissions = $query->select()->toArray();
return self::buildMenuTree($permissions, 0, $permissionCodes);
}
// 构建菜单树
private static function buildMenuTree($permissions, $parentId, $userPermissions)
{
$tree = [];
foreach ($permissions as $permission) {
if ($permission['parent_id'] == $parentId) {
// 检查是否有权限
if (!in_array($permission['code'], $userPermissions)) {
continue;
}
$children = self::buildMenuTree($permissions, $permission['id'], $userPermissions);
if ($children || $permission['route']) {
$tree[] = [
'id' => $permission['id'],
'name' => $permission['name'],
'route' => $permission['route'],
'children' => $children
];
}
}
}
return $tree;
}
}
控制器基类
<?php
namespace app\admin\controller;
use app\common\auth\AuthHelper;
use think\Controller;
use think\facade\Session;
class BaseController extends Controller
{
protected $user;
protected function initialize()
{
parent::initialize();
// 用户登录检查
if (!Session::has('user_id')) {
$this->redirect('/login');
}
// 获取当前用户信息
$this->user = \app\common\model\User::find(Session::get('user_id'));
// 判断是否超级管理员
$isAdmin = $this->user->hasRole('admin');
$this->assign('isAdmin', $isAdmin);
// 获取并分配菜单
$menus = $isAdmin ? $this->getAllMenus() : AuthHelper::getMenuTree();
$this->assign('menus', $menus);
// 获取用户信息
$this->assign('user', $this->user);
}
// 获取所有菜单(管理员)
private function getAllMenus()
{
return \app\common\model\Permission::where('type', 1)
->where('status', 1)
->order('sort', 'asc')
->select()
->toArray();
}
}
使用示例
在控制器中使用权限检查
<?php
namespace app\admin\controller;
class OrderController extends BaseController
{
// 订单列表(需要权限)
public function index()
{
// 自定义权限检查
if (!$this->user->hasPermission('order_view')) {
return json(['code' => 403, 'msg' => '没有订单查看权限']);
}
// 处理业务逻辑...
return $this->fetch();
}
// 删除订单(需要权限)
public function delete($id)
{
if (!$this->user->hasPermission('order_delete')) {
return json(['code' => 403, 'msg' => '没有订单删除权限']);
}
// 处理删除逻辑...
return json(['code' => 1, 'msg' => '删除成功']);
}
}
初始化权限数据
<?php
// think 命令行工具创建初始化脚本
namespace app\common\command;
use think\console\Command;
use think\console\Input;
use think\console\Output;
use think\Db;
class Init extends Command
{
protected function configure()
{
$this->setName('init')
->setDescription('初始化权限数据');
}
protected function execute(Input $input, Output $output)
{
// 创建超级管理员角色
$adminRole = new \app\common\model\Role();
$adminRole->name = 'admin';
$adminRole->description = '超级管理员';
$adminRole->id = 1;
$adminRole->save();
// 创建基础权限
$permissions = [
['name' => '用户管理', 'code' => 'user_manage', 'type' => 1, 'parent_id' => 0],
['name' => '用户列表', 'code' => 'user_list', 'type' => 2, 'parent_id' => 1],
['name' => '用户添加', 'code' => 'user_create', 'type' => 2, 'parent_id' => 1],
['name' => '用户编辑', 'code' => 'user_edit', 'type' => 2, 'parent_id' => 1],
['name' => '用户删除', 'code' => 'user_delete', 'type' => 2, 'parent_id' => 1],
['name' => '角色管理', 'code' => 'role_manage', 'type' => 1, 'parent_id' => 0],
['name' => '角色列表', 'code' => 'role_list', 'type' => 2, 'parent_id' => 6],
['name' => '权限管理', 'code' => 'permission_manage', 'type' => 1, 'parent_id' => 0],
];
$permissionIds = [];
foreach ($permissions as $item) {
$permission = new \app\common\model\Permission();
$permission->save($item);
$permissionIds[] = $permission->id;
}
// 给管理员分配所有权限
$adminRole->permissions()->attach($permissionIds);
// 创建管理员用户
$admin = new \app\common\model\User();
$admin->username = 'admin';
$admin->password = password_hash('admin123', PASSWORD_DEFAULT);
$admin->save();
// 给管理员分配角色
$admin->roles()->attach([1]);
$output->writeln('初始化完成');
}
}
这个完整的权限管理方案包含了:
- 数据库设计:用户、角色、权限表及关联表
- 模型层:核心模型的关联关系
- 中间件:权限校验
- 控制器:CRUD操作及权限分配
- 辅助类:权限缓存、菜单生成等
- 使用示例:控制器级权限控制、模板渲染等
你可以根据项目实际需求进行调整和扩展。