文章问题导向
RBAC权限管理是什么?如何设计数据库?如何实现?
如果你都有了答案,可以忽略本文章,或去nest学习导图寻找更多答案
阅前必知
阅读此文,需要有一定的数据库知识
此文并非最佳实践,只能参考,如果大家有好的设计与代码,欢迎留言
RBAC
RBAC是基于角色的权限访问控制(Role-Based Access Control)
一种数据库设计思想,根据设计数据库设计方案,完成项目的权限管理
在RBAC中,有3个基础组成部分,分别是:用户、角色和权限,权限与角色相关联,用户通过成为适当角色而得到这些角色的权限
- 权限:具备操作某个事务的能力
- 角色:一系列权限的集合
如:一般的管理系统中:
销售人员:仅仅可以查看商品信息
运营人员:可以查看,修改商品信息
管理人员:可以查看,修改,删除,以及修改员工权限等等
管理人员只要为每个员工账号分配对应的角色,登陆操作时就只能执行对应的权限或看到对应的页面
权限类型
展示(菜单),如:显示用户列表,显示删除按钮等等…
操作(功能),如:增删改查,上传下载,发布公告,发起活动等等…
数据库设计
数据库设计:可简单,可复杂,几个人使用的系统和几千人使用的系统是不一样的
小型项目:用户表,权限表
中型项目:用户表,角色表,权限表
大型项目:用户表,用户分组表,角色表,权限表,菜单表…
没有角色的设计
只有用户表,菜单表,两者是多对多关系,有一个关联表
缺点:
新建一个用户时,在用户表中添加一条数据
新建一个用户时,在关联表中添加N条数据
每次新建一个用户需要添加1+N(关联几个)条数据
如果有100个用户,每个用户100个权限,那需要添加10000条数据
基于RBAC的设计
用户表和角色表的关系设计:
如果你希望一个用户可以有多个角色,如:一个人即是销售总监,也是人事管理,就设计多对多关系
如果你希望一个用户只能有一个角色,就设计一对多,多对一关系
角色表和权限表的关系设计:
一个角色可以拥有多个权限,一个权限被多个角色使用,设计多对多关系
多对多关系设计
用户表与角色表是多对多关系,角色表与菜单表是多对多关系
更加复杂的设计
实现流程
- 数据表设计
- 实现角色的增删改查
- 实现用户的增删改查,增加和修改用户的时候需要选择角色
- 实现权限的增删改查
- 实现角色与授权的关联
- 判断当前登录的用户是否有访问菜单的权限
- 根据当前登录账户的角色信息动态显示左侧菜单(前端)
代码实现
这里将实现一个用户,部门,角色,权限的例子:
用户通过成为部门的一员,则拥有部门普通角色的权限,还可以单独给用户设置角色,通过角色,获取权限。
权限模块包括,模块,菜单,操作,通过type区分类型,这里就不再拆分。
关系总览:
用户 - 部门:一对多关系,这里设计用户只能加入一个部门,如果设计可以加入多个部门,设计为多对多关系
用户 - 角色:多对多关系,可以给用户设置多个角色
角色 - 部门:多对多关系,一个部门多个角色
角色 - 权限:多对多关系,一个角色拥有多个权限,一个权限被多个角色使用
数据库实体设计
用户
import {
Column,
Entity,
ManyToMany,
ManyToOne,
JoinColumn,
JoinTable,
PrimaryGeneratedColumn,
} from 'typeorm';
import {
RoleEntity } from '../../role/entities/role.entity';
import {
DepartmentEntity } from '../../department/entities/department.entity';
@Entity({
name: 'user' })
export class UsersEntity {
@PrimaryGeneratedColumn()
id: number;
@Column({
type: 'varchar',
length: 30,
nullable: false,
unique: true,
})
username: string;
@Column({
type: 'varchar',
name: 'password',
length: 100,
nullable: false,
select: false,
comment: '密码',
})
password: string;
@ManyToMany(() => RoleEntity, (role) => role.users)
@JoinTable({
name: 'user_role' })
roles: RoleEntity[];
@ManyToOne(() => DepartmentEntity, (department) => department.users)
@JoinColumn({
name: 'department_id' })
department: DepartmentEntity;
}
角色
import {
Entity,
PrimaryGeneratedColumn,
Column,
ManyToMany,
JoinTable,
} from 'typeorm';
import {
UsersEntity } from '../../user/entities/user.entity';
import {
DepartmentEntity } from '../../department/entities/department.entity';
import {
AccessEntity } from '../../access/entities/access.entity';
@Entity({
name: 'role' })
export class RoleEntity {
@PrimaryGeneratedColumn()
id: number;
@Column({
type: 'varchar', length: 30 })
rolename: string;
@