Skip to content

权限系统

系统采用经典的 RBAC(Role-Based Access Control) 模型,实现细粒度的权限控制。

权限模型

用户 (User) ←多对多→ 角色 (Role) ←多对多→ 菜单/按钮 (Menu/Btn)

三者关系:

  • 用户:系统的操作主体,一个用户可拥有多个角色
  • 角色:权限的载体,一个角色可绑定多个菜单和按钮权限
  • 菜单/按钮:具体的资源,菜单控制页面访问,按钮控制操作权限

权限控制流程

1. 用户登录 → 获取角色列表
2. 角色列表 → 获取菜单/按钮权限
3. 前端根据权限 → 动态生成路由和渲染按钮
4. 后端接口 → Guard 验证权限

后端实现

JWT 认证

所有接口默认需要 JWT Token 认证(使用 JwtAuthGuard)。

使用 @Public() 装饰器可以跳过认证:

typescript
@Public()
@Get('captcha')
getCaptcha() {
  return this.authService.getCaptcha();
}

权限守卫

使用 @RequirePermissions() 装饰器保护接口:

typescript
@Get(':id')
@RequirePermissions('system:user:query')
async findOne(@Param('id') id: string) {
  return this.userService.findOne(id);
}

只有拥有 system:user:query 权限标识的角色才能访问该接口。

装饰器总结

装饰器说明
@Public()跳过 JWT 认证
@RequirePermissions('xxx')要求指定权限
@Action('xxx')记录操作日志
@User()获取当前登录用户
@Original()返回原始数据,不经过响应拦截器包装

前端实现

动态路由

登录后前端调用 /auth/routes 获取当前用户的菜单列表,动态生成路由:

typescript
// 根据后端返回的菜单数据生成路由
const routes = menuListToRoutes(menus)
routes.forEach(route => router.addRoute(route))

v-auth 指令

使用 v-auth 指令控制按钮的显示/隐藏:

vue
<template>
  <el-button v-auth="'system:user:add'" type="primary">新增</el-button>
  <el-button v-auth="'system:user:edit'" type="warning">编辑</el-button>
  <el-button v-auth="'system:user:delete'" type="danger">删除</el-button>
</template>

如果用户没有对应的按钮权限,该元素会被自动隐藏。

权限判断

也可以在代码中手动判断权限:

typescript
const { permissions } = useUserStore()
if (permissions.includes('system:user:delete')) {
  // 有删除权限
}

权限标识规范

推荐使用 模块:资源:操作 的格式:

system:user:query   # 查询用户
system:user:add     # 新增用户
system:user:edit    # 编辑用户
system:user:delete  # 删除用户
system:user:export  # 导出用户
system:role:query   # 查询角色
system:role:add     # 新增角色
...

API 接口

方法路径说明
POST/auth/login用户登录
GET/auth/captcha获取验证码
GET/auth/routes获取用户菜单路由
GET/auth/allPermissions获取所有权限列表
GET/auth/userInfo获取当前用户信息
POST/auth/logout用户登出