权限管理
CarefreeCMS 提供了完善的权限管理系统,支持细粒度的权限控制,确保系统安全和数据隔离。
权限概述
RBAC 模型
CarefreeCMS 采用基于角色的访问控制(RBAC)模型:
用户 → 角色 → 权限
核心概念
- 用户(User):系统使用者
- 角色(Role):权限的集合
- 权限(Permission):具体的操作许可
工作流程
- 创建角色并分配权限
- 将用户分配到角色
- 用户获得角色的所有权限
- 系统根据权限控制访问
权限类型
菜单权限
- 控制菜单显示
- 左侧导航栏
- 顶部菜单
操作权限
- 查看(view)
- 添加(create)
- 编辑(update)
- 删除(delete)
- 导出(export)
数据权限
- 全部数据
- 本站点数据
- 本部门数据
- 本人数据
角色管理
系统角色
超级管理员
角色名称:超级管理员
标识:super_admin
说明:拥有所有权限,不受限制
权限:全部
数据范围:全部
管理员
角色名称:管理员
标识:admin
说明:站点管理员
权限:站点管理相关权限
数据范围:所属站点
编辑
角色名称:编辑
标识:editor
说明:内容编辑人员
权限:文章、分类、标签管理
数据范围:本人创建的内容
作者
角色名称:作者
标识:author
说明:内容创作者
权限:文章发布
数据范围:仅本人文章
创建角色
进入角色管理
系统管理 → 角色管理 → 添加角色填写基本信息
角色名称:内容审核员 角色标识:auditor 排序:10 状态:启用 备注:负责审核文章内容分配权限
- 勾选所需权限
- 支持树形结构
- 支持全选/反选
设置数据权限
数据范围: ⚪ 全部数据 ⚪ 本站点数据 ⚪ 本部门数据 ● 自定义数据权限 自定义规则: - 可查看所有待审核文章 - 可编辑待审核文章 - 不能删除已发布文章保存角色
编辑角色
- 在角色列表点击"编辑"
- 修改角色信息或权限
- 保存更改
注意事项
- 修改会影响所有该角色的用户
- 建议在测试环境先测试
- 重要角色修改前备份
删除角色
删除前检查
- 是否有用户使用该角色
- 是否是系统必需角色
删除方式
方式一:转移后删除
1. 将用户转移到其他角色
2. 删除空角色
方式二:强制删除
1. 删除角色
2. 用户变为无角色状态
3. 需重新分配角色
权限配置
权限列表
系统管理
系统管理
├── 系统设置
│ ├── 查看设置
│ └── 修改设置
├── 用户管理
│ ├── 用户列表
│ ├── 添加用户
│ ├── 编辑用户
│ └── 删除用户
├── 角色管理
│ ├── 角色列表
│ ├── 添加角色
│ ├── 编辑角色
│ └── 删除角色
└── 权限管理
├── 权限列表
├── 添加权限
├── 编辑权限
└── 删除权限
内容管理
内容管理
├── 文章管理
│ ├── 文章列表
│ ├── 添加文章
│ ├── 编辑文章
│ ├── 删除文章
│ ├── 审核文章
│ └── 发布文章
├── 分类管理
│ ├── 分类列表
│ ├── 添加分类
│ ├── 编辑分类
│ └── 删除分类
├── 标签管理
│ ├── 标签列表
│ ├── 添加标签
│ ├── 编辑标签
│ └── 删除标签
└── 媒体库
├── 文件列表
├── 上传文件
├── 编辑文件
└── 删除文件
站点管理
站点管理
├── 站点列表
├── 添加站点
├── 编辑站点
├── 删除站点
└── 站点配置
添加权限
进入权限管理
系统管理 → 权限管理 → 添加权限填写权限信息
权限名称:文章审核 权限标识:article.audit 上级权限:文章管理 权限类型:操作 排序:10 状态:启用设置权限规则
// 权限规则 [ 'path' => '/api/article/audit', 'method' => 'POST', 'controller' => 'Article', 'action' => 'audit', ]保存权限
权限继承
父子权限
文章管理(父权限)
├── 文章列表(子权限)
├── 添加文章(子权限)
└── 编辑文章(子权限)
规则:
- 拥有父权限 → 自动拥有所有子权限
- 无父权限 → 无法访问任何子权限
用户管理
用户列表
列表字段
用户名 姓名 角色 状态 最后登录 操作
admin 管理员 超级管理员 启用 2024-01-15 编辑/删除
editor1 编辑A 编辑 启用 2024-01-14 编辑/删除
author1 作者B 作者 禁用 2024-01-10 编辑/删除
筛选条件
角色:全部 | 超级管理员 | 管理员 | 编辑 | 作者
状态:全部 | 启用 | 禁用
关键词搜索:用户名、姓名、邮箱
添加用户
基本信息
用户名:editor001 密码:****** 确认密码:****** 姓名:张三 邮箱:editor001@example.com 手机:13800138000分配角色
主要角色:编辑 附加角色:内容审核员所属站点
☑ 主站 ☐ 分站A ☐ 分站B其他设置
状态:启用 允许登录:是 允许API访问:是保存用户
编辑用户
可编辑项
- 基本信息(不含用户名)
- 角色分配
- 所属站点
- 状态设置
重置密码
方式一:管理员重置
1. 编辑用户
2. 点击"重置密码"
3. 输入新密码
4. 保存
方式二:用户自行重置
1. 忘记密码
2. 邮箱验证
3. 设置新密码
删除用户
删除前确认
- 检查用户创建的内容
- 决定内容处理方式:
- 转移给其他用户
- 或一并删除
删除操作
- 点击"删除"按钮
- 选择内容处理方式
- 确认删除
权限验证
后端验证
中间件验证
// app/middleware/Auth.php
public function handle($request, \Closure $next)
{
// 验证登录
if (!$this->isLogin()) {
return json(['code' => 401, 'message' => '请先登录']);
}
// 验证权限
if (!$this->hasPermission($request)) {
return json(['code' => 403, 'message' => '无权限访问']);
}
return $next($request);
}
// 检查权限
private function hasPermission($request)
{
$user = $this->getUser();
$route = $request->pathinfo();
return $user->hasPermission($route);
}
控制器验证
// app/controller/Article.php
public function delete($id)
{
// 检查删除权限
if (!$this->auth->can('article.delete')) {
return $this->error('无删除权限');
}
// 检查数据权限
$article = Article::find($id);
if (!$this->canDelete($article)) {
return $this->error('您无权删除此文章');
}
// 执行删除
$article->delete();
return $this->success('删除成功');
}
// 数据权限验证
private function canDelete($article)
{
$user = $this->auth->user();
// 超级管理员
if ($user->isSuper()) {
return true;
}
// 站点管理员(本站点)
if ($user->isAdmin() && $article->site_id == $user->site_id) {
return true;
}
// 作者本人
if ($article->user_id == $user->id) {
return true;
}
return false;
}
前端验证
指令验证
<template>
<!-- 按钮权限控制 -->
<el-button v-permission="'article.create'">添加文章</el-button>
<el-button v-permission="'article.delete'">删除文章</el-button>
<!-- 区块权限控制 -->
<div v-permission="'admin.system'">
<h3>系统设置</h3>
<!-- 内容 -->
</div>
</template>
<script setup>
import { useAuth } from '@/composables/useAuth'
const auth = useAuth()
// 检查权限
const canCreate = auth.hasPermission('article.create')
const canDelete = auth.hasPermission('article.delete')
</script>
组件验证
<template>
<Permission permission="article.create">
<el-button>添加文章</el-button>
</Permission>
<Permission :permissions="['article.edit', 'article.delete']" mode="any">
<!-- 有编辑或删除权限即可显示 -->
</Permission>
<Permission :permissions="['article.edit', 'article.publish']" mode="all">
<!-- 需同时拥有编辑和发布权限 -->
</Permission>
</template>
路由守卫
// router/index.js
router.beforeEach((to, from, next) => {
// 检查登录
if (to.meta.requiresAuth && !store.getters.isLogin) {
next('/login')
return
}
// 检查权限
if (to.meta.permission) {
if (!store.getters.hasPermission(to.meta.permission)) {
next('/403')
return
}
}
next()
})
// 路由配置
{
path: '/article/create',
component: ArticleCreate,
meta: {
requiresAuth: true,
permission: 'article.create'
}
}
数据权限
权限范围
全部数据
// 可访问所有数据
$articles = Article::select();
本站点数据
// 只能访问所属站点的数据
$articles = Article::where('site_id', $user->site_id)->select();
本部门数据
// 只能访问本部门的数据
$articles = Article::where('department_id', $user->department_id)->select();
本人数据
// 只能访问自己创建的数据
$articles = Article::where('user_id', $user->id)->select();
数据过滤
模型作用域
// app/model/Article.php
class Article extends SiteModel
{
// 全局作用域:自动过滤站点
protected function base($query)
{
$user = auth()->user();
if ($user->isSuper()) {
// 超级管理员看全部
return $query;
}
if ($user->isAdmin()) {
// 管理员看本站点
return $query->where('site_id', $user->site_id);
}
// 普通用户看本人
return $query->where('user_id', $user->id);
}
}
查询构造器
// 根据权限自动过滤
$query = Article::query();
// 应用数据权限过滤
$query = $this->applyDataPermission($query, 'article');
// 获取数据
$articles = $query->paginate(20);
字段权限
敏感字段
// 根据权限控制字段显示
public function toArray()
{
$data = parent::toArray();
$user = auth()->user();
// 非管理员隐藏敏感字段
if (!$user->isAdmin()) {
unset($data['password']);
unset($data['secret_key']);
unset($data['api_token']);
}
return $data;
}
权限缓存
缓存权限
用户登录时缓存
// 登录成功后
$user = User::find($userId);
$permissions = $user->getAllPermissions();
// 缓存权限列表
Cache::set('user_permissions_' . $userId, $permissions, 3600);
获取权限
// 从缓存获取
$permissions = Cache::get('user_permissions_' . $userId);
if (!$permissions) {
// 缓存未命中,从数据库获取
$permissions = $user->getAllPermissions();
Cache::set('user_permissions_' . $userId, $permissions, 3600);
}
return $permissions;
更新缓存
角色权限变更时
// 更新角色权限后
public function updatePermissions($roleId, $permissions)
{
// 保存权限
Role::find($roleId)->permissions()->sync($permissions);
// 清除该角色所有用户的权限缓存
$users = User::where('role_id', $roleId)->select();
foreach ($users as $user) {
Cache::delete('user_permissions_' . $user->id);
}
}
用户角色变更时
// 修改用户角色后
public function updateRole($userId, $roleId)
{
User::update($userId, ['role_id' => $roleId]);
// 清除用户权限缓存
Cache::delete('user_permissions_' . $userId);
}
最佳实践
角色设计
最小权限原则
- 只授予必需权限
- 避免过度授权
- 定期审查权限
合理划分角色
✓ 好的设计:
- 超级管理员(全部权限)
- 站点管理员(站点管理)
- 内容编辑(内容管理)
- 内容审核(审核权限)
- 普通作者(发布文章)
✗ 差的设计:
- 管理员(权限太多)
- 普通用户(权限太少)
权限命名
统一规范
格式:模块.操作
示例:
- article.view(查看文章)
- article.create(创建文章)
- article.update(编辑文章)
- article.delete(删除文章)
- article.audit(审核文章)
安全建议
密码策略
长度:至少 8 位
复杂度:包含大小写字母、数字、特殊字符
有效期:90 天强制修改
历史:不能与前 3 次密码相同
登录安全
失败次数:5 次锁定
锁定时间:30 分钟
两步验证:支持短信/邮箱验证
登录日志:记录所有登录行为
会话管理
超时时间:2 小时
同时在线:允许 1 个设备
强制下线:支持
常见问题
如何给用户分配多个角色?
- 编辑用户
- 主要角色:选择主角色
- 附加角色:勾选其他角色
- 保存
用户将拥有所有角色的权限并集。
如何临时禁用用户?
- 编辑用户
- 状态改为"禁用"
- 保存
用户将无法登录,已登录会话失效。
如何查看用户的所有权限?
- 进入用户列表
- 点击用户的"权限"按钮
- 查看权限树
- 显示直接权限和继承权限
权限修改后需要重新登录吗?
实时生效
- 使用权限缓存
- 缓存过期后自动更新
- 无需重新登录
立即生效
- 清除权限缓存
- 用户下次请求时重新加载
如何实现IP白名单?
// middleware/IpWhitelist.php
public function handle($request, \Closure $next)
{
$ip = $request->ip();
$whitelist = config('app.ip_whitelist');
if (!in_array($ip, $whitelist)) {
return json(['code' => 403, 'message' => 'IP未授权']);
}
return $next($request);
}
