【NestJS】权限控制方案

有两种方案:

  • 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 个中间表。

相关推荐
亮子AI18 天前
【NestJS】为什么return不返回客户端?
前端·javascript·git·nestjs
小p19 天前
nestjs学习2:利用typescript改写express服务
nestjs
Eric_见嘉25 天前
NestJS 🧑‍🍳 厨子必修课(九):API 文档 Swagger
前端·后端·nestjs
XiaoYu20021 个月前
第3章 Nest.js拦截器
前端·ai编程·nestjs
XiaoYu20021 个月前
第2章 Nest.js入门
前端·ai编程·nestjs
实习生小黄1 个月前
NestJS 调试方案
后端·nestjs
当时只道寻常1 个月前
NestJS 如何配置环境变量
nestjs
濮水大叔2 个月前
VonaJS是如何做到文件级别精确HMR(热更新)的?
typescript·node.js·nestjs
ovensi2 个月前
告别笨重的 ELK,拥抱轻量级 PLG:NestJS 日志监控实战指南
nestjs