有两种方案:
- ACL (Access Control List)权限控制
- RBAC(Role Based Access Control)权限控制
ACL (Access Control List)权限控制
这种记录每个用户有什么权限的方式,叫做访问控制表(Access Control List)。
介绍
- 特点是用户直接和权限关联。
- 用户和权限是多对多关系,在数据库中会存在用户表、权限表、用户权限中间表。
- 登录的时候,把用户信息查出来,放到 session 或者 jwt 返回。
- 然后访问接口的时候,在 Guard 里判断是否登录,是否有权限,没有就返回 401,有的话才会继续处理请求。
使用
添加创建 user 模块:
sql
nest g resource user
添加 User 和 Permission 的 Entity:
js
import { Column, CreateDateColumn, Entity, PrimaryGeneratedColumn, UpdateDateColumn } from "typeorm";
@Entity()
export class User {
@PrimaryGeneratedColumn()
id: number;
@Column({
length: 50
})
username: string;
@Column({
length: 50
})
password: string;
@CreateDateColumn()
createTime: Date;
@UpdateDateColumn()
updateTime: Date;
}
User 有 id、username、password、createTime、updateTime 5 个字段。
js
import { Column, CreateDateColumn, Entity, PrimaryGeneratedColumn, UpdateDateColumn } from "typeorm";
@Entity()
export class Permission {
@PrimaryGeneratedColumn()
id: number;
@Column({
length: 50
})
name: string;
@Column({
length: 100,
nullable: true
})
desc: string;
@CreateDateColumn()
createTime: Date;
@UpdateDateColumn()
updateTime: Date;
}
permission 有 id、name、desc、createTime、updateTime 5 个字段,desc 字段可以为空。
然后在 User 里加入和 Permission 的关系,也就是多对多:
js
@ManyToMany(() => Permission)
@JoinTable({
name: 'user_permission_relation'
})
permissions: Permission[]
通过 @ManyToMany 声明和 Permisssion 的多对多关系。
多对多是需要中间表的,通过 @JoinTable 声明,指定中间表的名字。
然后在 TypeOrm.forRoot 的 entities 数组加入 entity UserPermission:
把 Nest 服务跑起来试试:
arduino
npm run start:dev
可以看到生成了 user、permission、user_permission_relation 这 3 个表。
并且中间表 user_permission_relation 还有 userId、permissionId 两个外键。
RBAC(Role Based Access Control)权限控制
这种记录每个用户有什么权限的方式,叫做访问控制表(Access Control List)。
介绍
- 相比于 ACL (access control list)的方式,多了一层角色,给用户分配角色而不是直接分配权限。
- 检查权限的时候还是要把角色的权限合并之后再检查是否有需要的权限的。
- 通过 jwt 实现了登录,把用户和角色信息放到 token 里返回。
- 添加了 LoginGuard 来做登录状态的检查。
- 然后添加了 PermissionGuard 来做权限的检查。
- LoginGuard 里从 jwt 取出 user 信息放入 request,PermissionGuard 从数据库取出角色对应的权限,检查目标 handler 和 controller 上声明的所需权限是否满足。
- LoginGuard 和 PermissionGuard 需要注入一些 provider,所以通过在 AppModule 里声明 APP_GUARD 为 token 的 provider 来注册的全局 Guard。
- 然后在 controller 和 handler 上添加 metadata 来声明是否需要登录,需要什么权限,之后在 Guard 里取出来做检查。
使用
添加创建 user 模块:
sql
nest g resource user
添加 User、Role、Permission 的 Entity: 用户、角色、权限都是多对多的关系。
js
import { Column, CreateDateColumn, Entity, PrimaryGeneratedColumn, UpdateDateColumn } from "typeorm";
@Entity()
export class User {
@PrimaryGeneratedColumn()
id: number;
@Column({
length: 50
})
username: string;
@Column({
length: 50
})
password: string;
@CreateDateColumn()
createTime: Date;
@UpdateDateColumn()
updateTime: Date;
@ManyToMany(() => Role)
@JoinTable({
name: 'user_role_relation'
})
roles: Role[]
}
User 有 id、username、password、createTime、updateTime 5 个字段。
通过 @ManyToMany 映射和 Role 的多对多关系,并指定中间表的名字。
然后创建 Role 的 entity:
js
import { Column, CreateDateColumn, Entity,PrimaryGeneratedColumn, UpdateDateColumn } from "typeorm";
@Entity()
export class Role {
@PrimaryGeneratedColumn()
id: number;
@Column({
length: 20
})
name: string;
@CreateDateColumn()
createTime: Date;
@UpdateDateColumn()
updateTime: Date;
@ManyToMany(() => Permission)
@JoinTable({
name: 'role_permission_relation'
})
permissions: Permission[]
}
Role 有 id、name、createTime、updateTime 4 个字段。
通过 @ManyToMany 映射和 Permission 的多对多关系,并指定中间表的名字。
js
import { Column, CreateDateColumn, Entity, PrimaryGeneratedColumn, UpdateDateColumn } from "typeorm";
@Entity()
export class Permission {
@PrimaryGeneratedColumn()
id: number;
@Column({
length: 50
})
name: string;
@Column({
length: 100,
nullable: true
})
desc: string;
@CreateDateColumn()
createTime: Date;
@UpdateDateColumn()
updateTime: Date;
}
Permission 有 id、name、createTime、updateTime 4 个字段。
然后在 TypeOrm.forRoot 的 entities 数组加入这三个 entity:
把 Nest 服务跑起来试试:
arduino
npm run start:dev
可以看到生成了 user、role、permission 这 3 个表,还有 user_roole_relation、role_permission_relation 这 2 个中间表。